> ## Documentation Index
> Fetch the complete documentation index at: https://docs.generalrobotics.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# IsaacArm

> Isaac Sim arm implementation backed by Zenoh

```python theme={null}
from grid_sim_client.isaac.robot import IsaacArm
```

Isaac Sim arm implementation backed by Zenoh.

This class provides an interface to control a simulated arm in Isaac Sim
using Zenoh clients for poses, joints, and gripper control.

## Constructor

```python Signature theme={null}
IsaacArm(
    config=default_isaac_config,
    clients: Optional[dict] = None,
    client_bundle: Optional[IsaacClientBundle] = None,
    *,
    robot_name: str = 'ur5e',
    grace_robot_name: Optional[str] = None,
    grace_ee_frame: Optional[str] = None,
    arm_joints: Optional[int] = None,
    arm_joint_names: Optional[list[str]] = None,
    grid_zero_offset: Optional[list[float]] = None,
    gripper_client_name: Optional[str] = None,
    capture_startup_zero_offset: bool = True,
    startup_zero_offset_timeout: float = 10.0,
)
```

## Properties

<ResponseField name="arms" type="Dict[str, 'Component']">
  Child components that are arms (derived, read-only).

  Filtered from `subcomponents` by `Arm` role; the returned dict
  is a fresh snapshot.
</ResponseField>

<ResponseField name="end_effector" type="Optional['Component']">
  The attached end effector, or `None` (derived, read-only).

  Returns the child named `"end_effector"` when it is an
  `EndEffector`, otherwise the first `EndEffector` child in
  insertion order. Attach one via
  `addSubcomponent("end_effector", ...)`.
</ResponseField>

<ResponseField name="expected_identity" type="ComponentIdentity">
  Hardware identity this component's config declared it should have.

  Set from the `identity` block of the config envelope by
  `from_config`, and empty for a component built any other
  way. Recording it acquires no hardware, and what it *means*
  splits by transport. For network-addressed hardware (an arm at a
  configured IP) it is a declaration to verify against: whether a
  mismatch warns or fails belongs to the caller that owns that
  policy, not to the driver. For bus-enumerated hardware (USB
  cameras), whose enumeration order is not a stable address, the
  declared `serial_number` is instead a *selector*: bring-up
  opens exactly that unit and fails loudly when it is absent,
  never falling back to a different device.

  Compare it against `getIdentity`, which is what the
  hardware reports.
</ResponseField>

<ResponseField name="home_pose" type="list">
  Placeholder home pose — updated dynamically when moveToNamedPose('home') is called.
</ResponseField>

<ResponseField name="sensors" type="Dict[str, 'Component']">
  Child components that are sensors (derived, read-only).

  Filtered from `subcomponents` by `Sensor` role; attach sensors
  via `addSensor`/`addSubcomponent` rather than writing to the
  returned dict, which is a fresh snapshot.
</ResponseField>

<ResponseField name="subcomponents" type="Dict[str, 'Component']">
  Mapping of child-component name to child component.

  The returned dict is the live backing store: mutating it mutates
  the component tree. Prefer `addSubcomponent` for inserts.
</ResponseField>

## Methods

### `addNamedPose()`

```python Signature theme={null}
addNamedPose(pose_name: str, joint_angles: List[float]) -> None
```

Define a pose\_name:joint\_angles pair in the dictionary of named poses
(overriding any existing pair).

<ParamField body="pose_name" required>
  Name of the pose to define
</ParamField>

<ParamField body="joint_angles" required>
  List of joint angles in radians
</ParamField>

**Raises:**

ValueError: If the length of joint\_angles list does match the length of other named
poses

### `addSensor()`

```python Signature theme={null}
addSensor(name: str, sensor: Sensor) -> None
```

Add an external sensor to the robot.

<ParamField body="name" type="str" required>
  Unique identifier for the sensor
</ParamField>

<ParamField body="sensor" type="Sensor" required>
  Sensor object to add (e.g. Camera, IMU, Lidar)
</ParamField>

**Returns:**

None

### `addSubcomponent()`

```python Signature theme={null}
addSubcomponent(name: str, component: 'Component') -> None
```

Attach a child component under a name.

An existing child with the same name is replaced, matching dict
assignment semantics (`addSensor` has always overwritten).

<ParamField body="name" required>
  Non-empty name for the child, unique within this component's `subcomponents`. Names are addressable as `getState` path chunks, so the path syntax characters `/ * ? [ ]` are not allowed.
</ParamField>

<ParamField body="component" required>
  The child component to attach.
</ParamField>

**Raises:**

ValueError: If `name` is not a non-empty string, or contains
a path syntax character.

### `builtin_subcomponents()`

```python Signature theme={null}
builtin_subcomponents() -> Dict[str, Dict[str, Any]]
```

Declare the children this class always ships with (customization point).

Hardware that is part of the component itself — a humanoid's head
camera, an arm's wrist camera, a base built into a mobile
manipulator — is declared here rather than constructed in
`__init__`, so one description drives both the runtime tree and
the static config tooling. The declaration is **pure data** in the
same shape an authored `subcomponents` entry uses:
`&#123;"&lt;child name>": &#123;"type": "&lt;registry name>", "args": &#123;...&#125;,
"subcomponents": &#123;...&#125;, "enabled": True&#125;&#125;`, where `type` names a
robot- or sensor-registry key, `args` are that class's config
args, `subcomponents` declares grandchildren by the same rules,
and `enabled` (default `True`) can declare a child off by
default.

An override must be callable on the bare class, without
instantiation and without importing a driver or touching hardware:
the setup-time stream resolver reads it off the registry class to
resolve a robot's camera streams on a machine that has none of the
hardware attached.

The base class materializes the declaration on every construction
path — a direct constructor call attaches the children once the
constructor returns, and `from_config` attaches them merged
with the authored `subcomponents` block (authored keys win, so an
entry with the same name retunes `args` or drops the child with
`enabled: false` — and may omit `type`, inheriting the one
declared here — while an entry naming a different `type` is an
error). Attached builtin children are ordinary subcomponents:
they appear in `serialize`, in `getState`, and in the
lifecycle walks, and a builtin `Camera` child is skipped when the
tree is built with `enable_cameras=False`.

**Returns:**

Mapping of child name to its config declaration. The default is
empty — a class with no builtin children.

### `captureStartupZeroOffset()`

```python Signature theme={null}
captureStartupZeroOffset(
    *,
    timeout: float = 10.0,
    overwrite: bool = False,
) -> Optional[list[float]]
```

Capture the simulator's startup joint state as the Grid zero offset.

The offset follows the existing Grid convention: Grace joint configs are
converted to simulator commands by subtracting `grid_zero_offset`.

### `configHash()`

```python Signature theme={null}
configHash(
    *,
    include_types: Optional[Tuple[type, ...]] = None,
    include_identity: bool = False,
    exclude_fields: AbstractSet[str] = frozenset(),
    type_prefix: bool = False,
) -> str
```

Hash this component's serialized config subtree.

A SHA-256 hex digest over the `serialize` output — the
config topology and args, not object identity and not
`getState` telemetry. Deterministic: the same tree with
the same options always produces the same digest, regardless of
dict insertion order. Touches no hardware; with
`include_identity` it hashes whatever identity is already
recorded (declared or previously read), triggering no new read.

Two hashes are comparable only when computed with the same
options; equality across differently-parameterized calls is
meaningless. Note that with `include_identity` the digest
changes as identity fields become known — a component reports
fields monotonically (some only once started), so hash at a
consistent point in the lifecycle when comparing across runs.

<ParamField body="include_types">
  When given, only tree nodes whose component is an instance of one of these classes are hashed; a non-matching node is pruned together with its entire subtree. `None` keeps every node.
</ParamField>

<ParamField body="include_identity" default="False">
  When True, each kept node's `identity` block (as `serialize` records it — hardware-read overlaid on declared) is included in the hash. When False the hash covers configuration only.
</ParamField>

<ParamField body="exclude_fields" default="frozenset()">
  Config `args` keys dropped from every kept node before hashing (e.g. an IP address that changes across networks).
</ParamField>

<ParamField body="type_prefix" default="False">
  When True, prepend this component's registry type and an underscore to the digest (e.g. `"go2_&lt;digest>"`, `"rig_&lt;digest>"` for a composite root) for a human-readable, greppable label. The type is already part of the hashed payload, so this only labels the same digest — the suffix after `_` is identical to the unprefixed call with the same options.
</ParamField>

**Returns:**

A 64-character lowercase SHA-256 hex digest, or
`"&lt;type>_&lt;digest>"` when `type_prefix` is True.

**Raises:**

RuntimeError: If this component was not constructed from a
config, so it cannot be serialized.
ValueError: If this component itself matches none of
`include_types` — the hash would cover an empty tree
and compare equal for unrelated components.

### `config_schema()`

```python Signature theme={null}
config_schema() -> dict[str, Any]
```

### `create_clients()`

```python Signature theme={null}
create_clients(client_config: dict, agent_config: Optional[dict] = None) -> None
```

Create Zenoh clients based on configuration.

<ParamField body="client_config" required>
  Dictionary of client configurations
</ParamField>

<ParamField body="agent_config">
  Optional dictionary of agent parameters
</ParamField>

### `endFreeDrive()`

```python Signature theme={null}
endFreeDrive() -> None
```

Exit free-drive mode and return to position control.

The arm is no longer movable by hand and again responds to
position-control commands such as `moveToPose` and
`setJointAngles`.

**Raises:**

NotImplementedError: If the arm does not support free-drive
mode.

### `followJointTrajectory()`

```python Signature theme={null}
followJointTrajectory(
    angles: List[List[float]],
    duration: Union[float, List[float]],
    blocking: bool = True,
) -> None
```

Move the arm through a sequence of joint configurations.

Each waypoint in `angles` is visited in order. The interpretation of
`duration` is uniform across implementations: a scalar is the *total*
trajectory time, split evenly across segments; a list specifies the
duration of each segment, where segment `i` is the move from the
previous pose (or the current arm pose, for `i=0`) to `angles[i]`,
so `len(duration)` must equal `len(angles)`.

Subclasses with a native trajectory-streaming API may blend between
waypoints; subclasses without one typically loop per-segment moves and
briefly stop at each waypoint. Either way the segment timings above
are honored.

<ParamField body="angles" required>
  Sequence of joint configurations (radians) to visit in order. Each inner list must have the same length as the arm's joint count.
</ParamField>

<ParamField body="duration" required>
  Either a single positive float giving the total trajectory time in seconds, or a list of positive floats with the same length as `angles` giving per-segment durations in seconds.
</ParamField>

<ParamField body="blocking" default="True">
  Wait for the trajectory to complete before returning. Defaults to True.
</ParamField>

**Raises:**

NotImplementedError: If the arm does not implement trajectory
following.
ValueError: If `angles` is empty, `duration` is not positive,
or list-form `duration` length does not match `angles`.

### `from_config()`

```python Signature theme={null}
from_config(config: Dict[str, Any], *, enable_cameras: bool = True) -> 'Component'
```

Construct this component and its config-declared subtree.

Recursive walk owned by the base class, the inverse of
`serialize`: the config envelope
(`&#123;"type": ..., "args": &#123;...&#125;, "subcomponents": &#123;...&#125;&#125;`) is
validated, this component is constructed from `args` via
`_from_config_args`, and each declared child is resolved
through the robot/sensor registries, constructed by its own
class's `from_config`, and attached. `type` may be omitted
when calling on a concrete class — it is then taken from the
class's registry entry.

The declared children are this class's
`builtin_subcomponents` overlaid by the config's
`subcomponents` block: builtin children first in declaration
order, then authored-only children. An authored entry whose name
matches a builtin one overlays it — its `args` merge over the
builtin `args` and `enabled: false` drops the child — rather
than colliding with it, and it may omit `type` entirely
(`&#123;"chassis_rear": &#123;"enabled": false&#125;&#125;` is a complete entry),
inheriting the builtin's; an entry naming a *different* `type`
than the builtin declaration is an error, as is an entry that
omits `type` while overlaying no builtin child. Any entry with
`enabled: false` is skipped, builtin or authored.

A node's optional `identity` block is recorded on the built
component as `expected_identity` — the hardware this entry
is *declared* to be. It is never checked against the device
here: construction acquires no hardware, and deciding what a
mismatch means belongs to the caller.

Component configs nested inside `args` (an arm's
`end_effector`, for example) are the constructor's business and
are built in `_from_config_args`; the recursion here covers
the `subcomponents` block only. The returned tree is
constructed but **not** started — use `make_robot`/
`make_sensor`, a `with` block, or an explicit
`start` call to bring it online.

<ParamField body="config" required>
  Config envelope for this component. Extra keys are rejected; `args` and `subcomponents` may be omitted.
</ParamField>

<ParamField body="enable_cameras" default="True">
  When True, camera components declared in the config are constructed and attached for local `getImage` use. When False, config-declared cameras are skipped at every depth because deploy streaming owns those devices; the flag is also passed to `_from_config_args` so a driver can skip cameras it builds itself.
</ParamField>

**Returns:**

The constructed component with its declared subcomponents
attached and its config recorded — including, per builtin
child, whether the authored config moved it off its
declaration's `enabled` state — so
`type(c).from_config(c.serialize())` rebuilds an equivalent
tree.

**Raises:**

ValueError: If `config` is not a mapping, a declared
subcomponent type is in neither registry, or an authored
entry overlays a builtin child with a different `type`.
ConfigValidationError: If the config tree does not match the
envelope shape; the message carries full config-tree
paths.

### `getEndEffectorPose()`

```python Signature theme={null}
getEndEffectorPose() -> Pose
```

```text theme={null}
[Deprecated]
Get the current end effector pose (position + orientation) w.r.t. the base frame.
```

### `getForce()`

```python Signature theme={null}
getForce(name: str = '') -> Force
```

Get force from named wrench client.

<ParamField body="name" default="''">
  Name of wrench client
</ParamField>

**Returns:**

Force reading from the wrench client.

### `getIdentity()`

```python Signature theme={null}
getIdentity() -> ComponentIdentity
```

Get this component's own hardware identity (serial, model, version, MAC).

Local, not recursive: it answers for this component alone. The
tree-wide view is `serialize`, which carries each node's
identity alongside its topology; identity is deliberately absent
from `getState`, which is live telemetry rather than
constants burned into a device.

**Never raises and never blocks the caller's real work.** A
driver read that fails — controller unreachable, dashboard
refused, SDK error — is logged and degrades to whatever fields
are already known, down to an empty mapping. Absence means
*unknown*, never *different*: see `ComponentIdentity` for what
consumers may conclude from a missing field.

**Callable in every lifecycle state** — before `start()`,
while started, after `stop()`, and after `shutdown()`. Where
the transport allows it (the UR dashboard server needs only the
controller IP, ZED serials are enumerable from sysfs before the
device is opened) a constructed-but-unstarted component already
answers, which is what lets a caller de-duplicate a robot before
bringing it up. Drivers that can only read identity from a live
device handle return nothing until then, so a call after
`start()` may carry *more* fields than one before it.

**Monotonic per component.** Every field ever read successfully
is cached, so repeated calls only ever gain fields — a later
failure never drops one that was already known. A field whose
value is re-read is updated to the fresh value.

**The field set is closed.** Only the fields `ComponentIdentity`
declares are accepted; anything else a driver reports is logged
and dropped, exactly like a non-string value, so what a component
reports always round-trips through the config envelope.

**Returns:**

A fresh `ComponentIdentity` mapping holding only the fields
known for this component; `&#123;&#125;` when nothing is known.
Mutating the result does not affect the component.

### `getImage()`

```python Signature theme={null}
getImage(camera_name: str = '', image_type: Optional[str] = 'rgb') -> Image
```

Get an image from a camera client.

<ParamField body="camera_name" default="''">
  Name of the image client to read from. If empty, selects the default camera based on image\_type.
</ParamField>

<ParamField body="image_type" default="'rgb'">
  Image type used to select the default camera. Accepts "rgb" or "depth".
</ParamField>

**Returns:**

Image: Captured image wrapped in the project's Image type.

**Raises:**

ValueError: If an invalid image\_type is provided.

### `getJointAngles()`

```python Signature theme={null}
getJointAngles() -> Optional[list]
```

Get the current joint angles of the arm.

**Returns:**

Optional\[list]: List of current joint angles in radians.

### `getJointStates()`

```python Signature theme={null}
getJointStates(name: str = 'joint_states') -> Optional[dict]
```

Get complete joint states from named joint angle client.

<ParamField body="name" type="str, optional" default="'joint_states'">
  Name of joint angle client
</ParamField>

**Returns:**

dict | None: Dictionary containing joint names, positions, velocities, and efforts, or
None if not available

**Raises:**

TypeError: If client is not a JointAngleClient

### `getJointVelocities()`

```python Signature theme={null}
getJointVelocities(name: str = 'joint_states') -> Optional[list]
```

Get joint velocities from named joint angle client.

<ParamField body="name" type="str, optional" default="'joint_states'">
  Name of joint angle client
</ParamField>

### `getLidarPointCloud()`

```python Signature theme={null}
getLidarPointCloud(lidar_name: str = '') -> Optional[PointCloud]
```

Get a point cloud from the named LiDAR sensor.

<ParamField body="lidar_name" type="str" default="''">
  Name of the lidar. If empty, uses the first available lidar.
</ParamField>

**Returns:**

Optional\[PointCloud]: The point cloud, or None if lidar not found

### `getMsg()`

```python Signature theme={null}
getMsg(name: str) -> dict
```

Get a message from a named generic client.

<ParamField body="name" type="str, optional">
  Name of the generic client
</ParamField>

### `getNamedPose()`

```python Signature theme={null}
getNamedPose(pose_name: str) -> Optional[List[float]]
```

Get the list of joint angles corresponding to a named pose.

<ParamField body="pose_name" required>
  Name of the pose to get (case-insensitive)
</ParamField>

**Returns:**

list: Joint angles (radians) of the named pose, or None if the named pose does not exist

### `getObjectPose()`

```python Signature theme={null}
getObjectPose(name: str = 'get_object_pose') -> Optional[Tuple[Position, Orientation]]
```

### `getOrientation()`

```python Signature theme={null}
getOrientation() -> Orientation
```

Get the current orientation of the end effector.

**Returns:**

Orientation: Current orientation of the end effector as a quaternion (x, y, z, w).

### `getPose()`

```python Signature theme={null}
getPose() -> Pose
```

Get the current end effector pose w\.r.t. the base frame.

**Returns:**

Pose: Current end effector pose.

### `getPosition()`

```python Signature theme={null}
getPosition() -> Optional[Position]
```

Get the current position of the end effector.

**Returns:**

Optional\[Position]: Current position of the end effector.

### `getState()`

```python Signature theme={null}
getState() -> dict
```

Get the current state of the arm.

**Returns:**

dict: Current state including position, orientation, and joint positions.

### `getTorque()`

```python Signature theme={null}
getTorque(name: str = '') -> Torque
```

Get torque from named wrench client.

<ParamField body="name" default="''">
  Name of wrench client
</ParamField>

**Returns:**

Torque reading from the wrench client.

### `grasp()`

```python Signature theme={null}
grasp()
```

Close the gripper.

**Returns:**

None

### `moveToDeltaPose()`

```python Signature theme={null}
moveToDeltaPose(
    delta_pose: Pose,
    blocking: bool = True,
    *,
    moving_time: float = 0.3,
    accel_time: float = 0.15,
)
```

Move the end effector to a relative pose.

<ParamField body="delta_pose" required>
  Desired relative pose offset of the end effector.
</ParamField>

<ParamField body="blocking" default="True">
  Whether to block until the move completes. (unused)
</ParamField>

<ParamField body="moving_time" default="0.3">
  Time allowed for movement in seconds. (unused)
</ParamField>

<ParamField body="accel_time" default="0.15">
  Acceleration time in seconds. (unused)
</ParamField>

**Returns:**

None

### `moveToHome()`

```python Signature theme={null}
moveToHome(blocking: bool = True) -> None
```

Move the arm to its predefined home pose.

Equivalent to `moveToNamedPose("home", blocking=blocking)`. The
`"home"` entry is registered in `named_poses` from the abstract
`home_pose` property during `Arm.__init__`, so every concrete
arm has it. Subclasses may add hardware-specific tuning parameters as
keyword-only arguments after `blocking`.

<ParamField body="blocking" default="True">
  Wait for movement to complete. Defaults to True.
</ParamField>

### `moveToNamedPose()`

```python Signature theme={null}
moveToNamedPose(
    pose_name: str,
    blocking: bool = True,
    *,
    moving_time: float = 2.0,
    accel_time: float = 0.75,
) -> None
```

Move to a named pose. For 'home', resolves joint count at runtime.

<ParamField body="pose_name" required>
  Name of the pose (case-insensitive).
</ParamField>

<ParamField body="blocking" default="True">
  Wait for movement to complete. (unused)
</ParamField>

<ParamField body="moving_time" default="2.0">
  Time to complete the movement in seconds. (unused)
</ParamField>

<ParamField body="accel_time" default="0.75">
  Time to accelerate/decelerate in seconds. (unused)
</ParamField>

**Raises:**

ValueError: If pose\_name is not found, or if getJointAngles() returns None for 'home'.

### `moveToPose()`

```python Signature theme={null}
moveToPose(
    pose: Optional[Pose | Position] = None,
    orientation: Optional[Orientation | list | np.ndarray] = None,
    blocking: bool = True,
    *,
    position: Optional[Position | list | np.ndarray] = None,
    moving_time: float = 0.3,
    accel_time: float = 0.15,
    relative: bool = False,
    ik_tolerance: float = 0.005,
    position_tolerance: float = 0.05,
) -> bool
```

Move the end effector to an absolute pose using Grace IK.

<ParamField body="pose">
  Target pose, or target position when `orientation` is supplied.
</ParamField>

<ParamField body="orientation">
  Target orientation as an Orientation, quaternion, or RPY vector.
</ParamField>

<ParamField body="blocking" default="True">
  Whether to wait for movement completion.
</ParamField>

<ParamField body="position">
  Keyword-only target position used by ROS pose callbacks.
</ParamField>

<ParamField body="moving_time" default="0.3">
  Time allowed for movement in seconds.
</ParamField>

<ParamField body="accel_time" default="0.15">
  Acceleration time in seconds.
</ParamField>

<ParamField body="relative" default="False">
  Whether the supplied position is relative to the current EE position.
</ParamField>

<ParamField body="ik_tolerance" default="0.005">
  Grace IK convergence tolerance.
</ParamField>

<ParamField body="position_tolerance" default="0.05">
  Maximum acceptable Cartesian IK error.
</ParamField>

**Returns:**

True if Grace found an IK solution and joint command publishing succeeded.

### `planToPose()`

```python Signature theme={null}
planToPose(
    pose: Optional[Pose | Position] = None,
    orientation: Optional[Orientation | list | np.ndarray] = None,
    blocking: bool = True,
    *,
    position: Optional[Position | list | np.ndarray] = None,
    pointcloud: Optional[list | np.ndarray] = None,
    goal_config: Optional[list | np.ndarray] = None,
    planner: str = 'aorrtc',
    max_iterations: int = 1000000,
    filter_robot: bool = True,
    path_step_s: float = 0.1,
    ik_tolerance: float = 0.005,
    position_tolerance: float = 0.05,
    wait_timeout: Optional[float] = None,
) -> bool
```

Plan a collision-free path to a pose with Grace/VAMP and execute it.

<ParamField body="pose">
  Target pose, or target position when `orientation` is supplied.
</ParamField>

<ParamField body="orientation">
  Target orientation as an Orientation, quaternion, or RPY vector.
</ParamField>

<ParamField body="blocking" default="True">
  Whether to wait for the final waypoint to be reached.
</ParamField>

<ParamField body="position">
  Keyword-only target position.
</ParamField>

<ParamField body="pointcloud">
  Obstacle points `[x, y, z]` in the robot base frame.
</ParamField>

<ParamField body="goal_config">
  Pre-validated Grace joint configuration to drive to instead of re-solving IK for the pose — a fresh solve can land on a different arm branch than the one that was validated.
</ParamField>

<ParamField body="planner" default="'aorrtc'">
  Grace/VAMP planner name (e.g. "aorrtc", "rrtc").
</ParamField>

<ParamField body="max_iterations" default="1000000">
  Maximum planner iterations.
</ParamField>

<ParamField body="filter_robot" default="True">
  Filter robot self-points out of the pointcloud.
</ParamField>

<ParamField body="path_step_s" default="0.1">
  Delay between streamed path waypoints.
</ParamField>

<ParamField body="ik_tolerance" default="0.005">
  Grace IK convergence tolerance (pose goals).
</ParamField>

<ParamField body="position_tolerance" default="0.05">
  Maximum acceptable Cartesian IK error (pose goals).
</ParamField>

<ParamField body="wait_timeout">
  Readback wait timeout for the final waypoint.
</ParamField>

**Returns:**

True if planning succeeded and the final waypoint command was
published (and, when blocking, reached).

### `prompt()`

```python Signature theme={null}
prompt() -> None
```

### `publishMsg()`

```python Signature theme={null}
publishMsg(msg: dict, name: str) -> None
```

Publish a message to a named generic client.

<ParamField body="msg" required>
  Message to publish
</ParamField>

<ParamField body="name" required>
  Name of the generic client
</ParamField>

### `release()`

```python Signature theme={null}
release()
```

Open the gripper.

**Returns:**

None

### `removeNamedPose()`

```python Signature theme={null}
removeNamedPose(pose_name: str) -> Optional[List[float]]
```

Remove a named pose from the dictionary of pose\_name:joint\_angles pairs.

<ParamField body="pose_name" required>
  Name of the pose to remove (case-insensitive)
</ParamField>

**Returns:**

list: Joint angles (radians) of the named pose that was removed, or None if the named
pose did not exist

### `reset()`

```python Signature theme={null}
reset(name: str = 'reset') -> None
```

### `run()`

```python Signature theme={null}
run() -> None
```

Run all Zenoh clients

### `sendPose()`

```python Signature theme={null}
sendPose(
    position: Position,
    orientation: Optional[Orientation] = None,
    name: str = 'cmd_delta_pose',
) -> None
```

Send pose command to named pose client.

<ParamField body="position" required>
  Target position
</ParamField>

<ParamField body="orientation">
  Target orientation (defaults to \[0,0,0,1] if None)
</ParamField>

<ParamField body="name" default="'cmd_delta_pose'">
  Name of pose client
</ParamField>

**Raises:**

TypeError: If client is not a PoseClient
ValueError: If client is not in talker mode

### `sendVelocity()`

```python Signature theme={null}
sendVelocity(linear_vel: Velocity, angular_vel: Velocity, name: str = 'cmd_vel') -> None
```

Send velocity command to named velocity client.

<ParamField body="linear_vel" required>
  Linear velocity components
</ParamField>

<ParamField body="angular_vel" required>
  Angular velocity components
</ParamField>

<ParamField body="name" default="'cmd_vel'">
  Name of velocity client
</ParamField>

**Raises:**

TypeError: If client is not a VelocityClient
ValueError: If client is not in talker mode

### `serialize()`

```python Signature theme={null}
serialize() -> Dict[str, Any]
```

Serialize this component tree back to its config envelope.

The exact inverse of `from_config`, producing the recursive
config schema it consumes:
`&#123;"type": ..., "args": &#123;...&#125;, "subcomponents": &#123;name: &lt;node>&#125;&#125;`,
minimized via `model_dump(exclude_defaults=True)` so empty
`args`/`subcomponents` are omitted. Only config-declared
children (those constructed through `from_config`) are
emitted; parts a driver constructs internally are implied by the
parent's `args` and reappear on reconstruction.

A child a class ships with (`builtin_subcomponents`) is
normally implied by the parent's `type` and needs no
`enabled` key. It gets an explicit one exactly when its
attached state diverges from what the bare class declaration
would produce, because reconstruction would otherwise flip it:

* declared enabled but switched off by the config
  (`enabled: false`) — emitted as a bare
  `&#123;"enabled": false&#125;` stub under `subcomponents`, the
  type-omitted overlay form that inherits the declaration's
  `type`. The stub exists only in this output; it is never a
  phantom entry in `subcomponents`, `getState`, or
  introspection.
* declared `enabled: false` but switched on by the config
  (`enabled: true`) — its normal serialized entry additionally
  carries `"enabled": true`, which an omitted key would not
  preserve (an authored entry that omits `enabled` keeps the
  declaration's value).

A child whose state matches its declaration is emitted exactly as
before, with no `enabled` key and no stub.

The asymmetry to
know: children skipped because the tree was built with
`enable_cameras=False` get **no** stub. That flag is
factory-only camera-ownership semantics — deploy streaming owns
those devices for this process, the config never said to drop
them — so the serialized config keeps describing the robot's
cameras, and passing the flag again is what skips them again.

A node also carries an `identity` block —
`&#123;"serial_number": ..., "model": ..., "controller_version":
..., "mac_address": ...&#125;`, each key present only when known —
whenever this component has a hardware identity to record, so the serialized
tree says which physical units it was built from and not just
which types. It is what `getIdentity` reports overlaid on
the identity the config declared (`expected_identity`), so
hardware that has identified itself wins over the declaration
while an unread declaration survives the round-trip. Omitted
entirely when nothing is known — never an empty block.

**Returns:**

The minimal config mapping such that
`make_robot(component.serialize())` reconstructs an
equivalent component tree.

**Raises:**

RuntimeError: If this component was not constructed from a
config, so no config type is recorded.
ConfigValidationError: If the recorded config does not fit
the envelope (e.g. a recorded arg key is not a string).

### `setJointAngles()`

```python Signature theme={null}
setJointAngles(
    angles: list,
    blocking: bool = True,
    *,
    velocities: Optional[list] = None,
    moving_time: float = 2.0,
    accel_time: float = 0.5,
    wait_timeout: Optional[float] = None,
    joint_tolerance: float = 0.25,
    settle_tolerance: float = 0.01,
    velocity_tolerance: float = 0.05,
    settle_samples: int = 3,
    poll_s: float = 0.05,
) -> bool
```

Set the joint angles of the arm.

<ParamField body="angles" required>
  List of joint angles for the robot in radians.
</ParamField>

<ParamField body="blocking" default="True">
  Whether to wait for joint readback to reach the target.
</ParamField>

<ParamField body="moving_time" default="2.0">
  Time allowed for movement in seconds.
</ParamField>

<ParamField body="accel_time" default="0.5">
  Acceleration time in seconds.
</ParamField>

<ParamField body="wait_timeout">
  Optional readback wait timeout. Defaults to movement timing plus a small margin.
</ParamField>

<ParamField body="joint_tolerance" default="0.25">
  Maximum per-joint target error in radians.
</ParamField>

<ParamField body="settle_tolerance" default="0.01">
  Maximum per-poll joint delta when velocities are unavailable.
</ParamField>

<ParamField body="velocity_tolerance" default="0.05">
  Maximum per-joint velocity for settling.
</ParamField>

<ParamField body="settle_samples" default="3">
  Number of consecutive settled polls required.
</ParamField>

<ParamField body="poll_s" default="0.05">
  Joint readback polling interval.
</ParamField>

### `setObjectPose()`

```python Signature theme={null}
setObjectPose(
    position: Position,
    orientation: Optional[Orientation] = None,
    name: str = 'set_object_pose',
) -> None
```

### `setup()`

```python Signature theme={null}
setup(
    *,
    robot_name: Optional[str] = None,
    grace_robot_name: Optional[str] = None,
    grace_ee_frame: Optional[str] = None,
    arm_joints: Optional[int] = None,
    arm_joint_names: Optional[list[str]] = None,
    grid_zero_offset: Optional[list[float]] = None,
    gripper_client_name: Optional[str] = None,
) -> None
```

Configure Grace-backed pose planning for this simulated arm.

### `setup_shutdown_handlers()`

```python Signature theme={null}
setup_shutdown_handlers() -> None
```

Register the process-wide atexit and signal handlers for safe teardown.

Installs an `atexit` hook and SIGINT/SIGTERM (and SIGHUP where
available) handlers that shut down every enrolled bring-up entry
point, newest first, so hardware is released on normal
termination and on Ctrl+C. Registration normally happens
automatically the first time a component is enrolled from the
main thread; call this explicitly from the main thread when
components are only ever brought up from background threads,
where Python forbids installing signal handlers — enrollment
there defers the atexit hook together with the signal handlers.

### `shutdown()`

```python Signature theme={null}
shutdown() -> None
```

Shut down this component's tree, halting motion and releasing resources.

Two phases, both owned by the base class. First a tree-wide
`stop`: motion is halted everywhere before anything is torn
down, so no part of the robot is still commandable while another
part is being released. Then the teardown walk — every
subcomponent is shut down first (children before their parent,
leaf-to-root; siblings in `subcomponents` insertion order),
then this component's own `_shutdown_self` hook runs.
Children-first ordering is a contract for shared resources: a
parent that owns a resource its children borrow (e.g. one ROS
node shared by both arms) releases it in its own hook, after all
children have shut down — a child must never release a resource
it does not own.

Idempotent: the first call latches, and every later call is a
no-op; the tree-wide stop also runs once, so a nested
`shutdown()` reached by the walk does not re-stop its subtree.
Best-effort: the stop phase and every hook failure are logged and
the walk continues, so this method never raises — it can run
safely from `__exit__`, signal handlers, and interpreter-exit
hooks. Blocks until every hook has returned; the component is
unusable afterwards.

Shutting down also drops the component from process-wide exit
cleanup (the enrollment made by the public `start`), so
the atexit/signal handlers only ever touch components that are
still live.

Subclasses must not replace this method — per-component cleanup
belongs in `_shutdown_self`. An override may only *extend*
the walk and must delegate to `super().shutdown()`; it must
never re-implement the recursion.

### `start()`

```python Signature theme={null}
start() -> None
```

Bring this component's tree online (connect, enable, arm).

Recursive walk owned by the base class and the mirror of
`shutdown`. Per node the walk runs `_start_self`,
then `_provision_children`, then descends into every
subcomponent (parents before their children, root-to-leaf;
siblings in `subcomponents` insertion order). That ordering is
the resource-handoff contract: a parent creates the runtime
resources its children borrow (an RTDE connection, a ROS node) in
its own bring-up hook and hands them to its children in
`_provision_children`, before any child hook runs.

**Warning: bring-up hooks move hardware.** `start()` is not a
passive connect. Driver hooks power on, enable, home, calibrate,
or stand a robot up — a Robotiq gripper strokes its jaws to
auto-calibrate, a WidowX homes, a Flexiv enables and homes its
gripper, a Go2 stands up. Restarting a tree re-runs those hooks,
so `stop()` then `start()` repeats that motion. Clear the
workspace before starting or restarting a physical robot; each
driver's `_start_self` documents the motion it commands.

Idempotent: the walk always descends the whole tree, but a
component whose bring-up hook already ran — and whose
`_still_live` health hook still reports it live — is
skipped, so calling `start()` twice re-runs no bring-up and
calling it after attaching a new subcomponent brings up only the
newcomer. A started component whose health hook reports its
resources dead (a power-cycled controller, a dropped connection)
gets its bring-up re-run, so `start()` alone is the recovery
call after such a fault.
`_provision_children` runs on every descent through a node
regardless of that mark, so a newcomer is provisioned by its
parent before its own hook runs. `stop` re-arms every
component it visits, so `stop()` then `start()` re-runs the
bring-up hooks (reconnect-after-fault) — while leaving the stopped
tree callable throughout. Blocks until every hook has returned.

Fail-fast: the first failing hook aborts the walk and
`ComponentStartError` is raised — a half-started component is
never handed back to the caller. Cleanup is scoped to this call:
the components this walk brought up for the first time are shut
down (best-effort) and the failing subtree is released, while
components that were already live before the call keep running
and the tree is not latched. On an initial bring-up nothing was
live, so that scope is the whole tree. Components this walk was
*restarting* (started before, re-armed by `stop`) are only
stopped, never shut down — a failed reconnect (e.g. a robot still
in an emergency stop) stays retryable with another `start()`.
A subtree that was already shut down is skipped with a warning
rather than resurrected.

Calling this method also enrolls the component in process-wide
exit cleanup: the atexit/signal handlers shut down every
component whose public `start()` was called (a tree root, or a
subtree driven directly) and that has not been shut down yet, so
hardware is released on normal termination and Ctrl+C once the
handlers are installed — automatic on the first main-thread
enrollment; a process that only brings components up from
background threads must call `setup_shutdown_handlers`
from its main thread. `shutdown` unenrolls.

Subclasses must not replace this method — per-component bring-up
belongs in `_start_self`. An override may only *extend* the
walk by delegating to `super().start()`; it must never
re-implement the recursion.

**Raises:**

RuntimeError: If this component has already been shut down;
`shutdown()` is final, so a new object is required.
ComponentStartError: If a bring-up hook raised. Whatever this
call brought up has been released by the time it
propagates, and the original failure is the exception's
`__cause__`.

### `startFreeDrive()`

```python Signature theme={null}
startFreeDrive() -> None
```

Enable free-drive (hand-guided) mode.

The arm becomes compliant and can be moved by hand while supporting
its own weight. Position-control commands such as
`moveToPose` and `setJointAngles` are not active in
this mode — call `endFreeDrive` to return to position
control.

**Raises:**

NotImplementedError: If the arm does not support free-drive
mode.

### `stop()`

```python Signature theme={null}
stop(immediate: bool = False)
```

Stop the robot.

<ParamField body="immediate" default="False">
  Whether to stop immediately. (unused)
</ParamField>

**Returns:**

None

### `validateGrasp()`

```python Signature theme={null}
validateGrasp() -> bool
```

Check whether the end effector is currently holding an object.

Thin wrapper that delegates to the configured end effector's
`EndEffector.getGripDetected`. Subclasses generally do not
need to override this.

**Returns:**

True if the end effector reports an object in its grip, False
otherwise.

**Raises:**

RuntimeError: If no end effector is configured on this arm.
NotImplementedError: If the configured end effector does not
support grip detection.


## Related topics

- [Customizing RL Training](/simulation/isaac/reinforcement-learning/customizing-training.md)
- [Training Workflow](/simulation/isaac/reinforcement-learning/training-workflow.md)
- [VR Teleop Guide](/simulation/isaac/teleoperation/vr-teleop-guide.md)
- [RemoteRobot](/python-api/grid-nexus-client/remoterobot.md)
- [Camera Calibration](/deployment/camera-calibration.md)
