> ## 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.

# Ghost Robotics Vision60 + Ghost Arm

> The Ghost Robotics Vision60 + Ghost Arm as GRID drives it

The Ghost Robotics Vision60 + Ghost Arm as GRID drives it — what this robot actually implements, with the signatures it actually accepts.

`connect("<name>")` returns a `RemoteRobot`. Its attributes are the methods and subcomponents below, and every call runs on the robot; the driver behind it is `Vision60WithArm`. Connecting neither starts nor moves the robot — it attaches to one that is already up. A method that fails on the robot arrives as `RuntimeError` naming the original error in its message. The client packages this page uses are preinstalled in every GRID session workspace and in the Python environment the GRID CLI prepares when you run a program with `skill run`; there is nothing to install.

```python theme={null}
from grid_nexus_client import connect

robot = connect("<vision60_arm-name>")

# `front_left` is a built-in camera: reach it as an attribute.
frame = robot.front_left.getImage()
rgb = frame.decode()                    # -> H x W x 3 RGB ndarray
```

## Methods on the robot

Called as `robot.<method>(...)`.

### `cleanup()`

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

Shut down the robot tree; alias kept for the historical Vision60 API.

Equivalent to `shutdown()`: recursive, idempotent, best-effort.

### `enableWalking()`

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

Enable walking mode for the robot.

### `getGPS()`

```python Signature theme={null}
getGPS() -> Optional[dict]
```

Return latest GPS data: position, orientation, linear & angular velocity.

**Returns:**

A dict with `position`, `orientation`, `linear_velocity`,
and `angular_velocity` — or `None` if no GPS message has
been received yet.

### `getIMU()`

```python Signature theme={null}
getIMU() -> Optional[dict]
```

Get the latest IMU reading.

**Returns:**

A dict with `orientation`, `angular_velocity`, and
`linear_acceleration` — or `None` if no IMU message has
been received yet.

### `getImage()`

```python Signature theme={null}
getImage(camera_name: str = '', **kwargs) -> Image
```

Return the image of camera.

Which camera a no-argument call reads is decided by cardinality
alone — no robot, config, or class declares a default. A robot with
exactly one camera needs no name; a robot with several requires one,
so adding a second camera never silently changes which one a bare
`getImage()` returns.

<ParamField body="camera_name" type="str" default="''">
  Name of the camera to get image from — either a directly attached camera's name or a `/`-separated path through subcomponents to a nested one (`left_arm/wrist`). May be omitted when the robot has exactly one camera.
</ParamField>

<ParamField body="**kwargs">
  Forwarded to the underlying sensor's `getImage`. Lets callers pass camera-specific options (e.g. `image_type="depth"`, `compressed=False`) without the base class having to enumerate them.
</ParamField>

**Returns:**

Image: The captured image.

**Raises:**

RuntimeError: If no cameras are configured, or the name is
omitted on a robot with more than one camera; the message
lists every configured camera path.
KeyError: If camera\_name is given but names no camera on this robot.

### `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

### `getOrientation()`

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

Get the robot orientation from odometry data.

**Returns:**

World-frame orientation, or `None` if no odometry message
has been received yet.

### `getPoseRel()`

```python Signature theme={null}
getPoseRel() -> Optional[Pose]
```

Return the body pose from the Vision60 `mcu/state/rel_pose` topic.

Ghost's firmware publishes this as a PoseStamped where the orientation
is the body's attitude relative to a gravity-aligned ground frame
(from the onboard IMU/EKF). The position field does not carry a
world-frame position — on the hardware sampled, x and y read zero and z
a small non-zero value — so use `getPosition()` / `getState()` when
world-frame position is what's wanted.

**Returns:**

Body pose whose orientation is the gravity-relative attitude and
whose position is not a world-frame position, or `None` if no
message has been received yet.

### `getPosition()`

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

Get the robot position from odometry data.

**Returns:**

World-frame position, or `None` if no odometry message
has been received yet.

### `getState()`

```python Signature theme={null}
getState(keys: Optional[Union[str, List[str]]] = None) -> Dict[str, Any]
```

Get a live state snapshot of this component's tree.

Recursive walk owned by the base class, following the lifecycle
template: each class contributes only the protected local hook
`_local_state`, and the walk composes the per-component
results into one nested mapping. Subclasses must not replace
this method — per-component state belongs in `_local_state`.

With no `keys`, returns this component's local state merged
with one nested node per subcomponent name — the tree structure
is the nesting itself, and the names mirror `subcomponents`
(and therefore `serialize()` and edge introspection): a
two-arm rig returns `&#123;"left_arm": &#123;"joint_positions": ...&#125;,
"right_arm": &#123;...&#125;&#125;`, and a leaf component returns its local
state alone. A component whose state could not be read (dead
telemetry, not yet started, already shut down) carries an
`"error"` entry — `&#123;"error": "&lt;ExceptionType>: &lt;message>"&#125;`,
with its children still nested alongside — instead of its state
keys. Errors are contained per node: one failing component never
loses the rest of the snapshot, and the walk still descends into
the failing component's children. `"error"` is reserved for
that purpose, and local state keys must not collide with
subcomponent names; a hook violating either is reported as that
node's error.

With `keys`, returns a flat mapping with one entry per match.
Each key is a `/`-separated path through the component tree:
every segment names a subcomponent, and the final segment may
instead name an entry in that component's local state. Because
structure is the nesting, a literal path is the same as plain
indexing — `getState(["left_arm/joint_positions"])` returns
the value of `getState()["left_arm"]["joint_positions"]` — and
a path ending on a subcomponent yields that component's full
nested node. Segments may use shell-style wildcards over
subcomponent names — `*` matches within one chunk and `**`
matches any chain of chunks — so `"*_arm/joint_positions"`
fans out to one entry per arm, keyed by the concrete matched
path. Wildcards never match state entries; only a literal final
segment does. A key that matches nothing raises, so a typo is
loud rather than silently absent. A matched component whose
state read failed yields `&#123;"error": "..."&#125;` at its path.

Keyed reads are lazy: a hook runs only where a key lands — a
literal path executes the final component's hook alone (not the
nodes traversed on the way), a glob executes only the matched
nodes, and each component's hook runs at most once per call
however many keys reach it. Components with a selective-read
hook (`_local_state_entries` — every `Robot` with
registered state getters) go further and execute only the getters a key names, so
a `**` glob probes their registries without touching
hardware. The caller pays only for the state actually
requested; `**` and the no-`keys` form visit the whole tree
because that is the request.

State is cheap by convention: local state carries kinematics,
status, and health — never bulk sensor payloads (camera frames,
point clouds, scans), which stay in their dedicated methods
(`getImage`, `getPointCloud`, ...). Callable on a stopped
tree — reading state after a soft e-stop is when it matters most
— and on a partially started one, where unstarted components
report a per-node error instead of failing the call.

<ParamField body="keys">
  State paths to read, or None for the full nested snapshot. A single string is shorthand for a one-element list.
</ParamField>

**Returns:**

The nested state snapshot when `keys` is None, otherwise a
flat mapping of matched path to state value or nested node.

**Raises:**

TypeError: If `keys` is neither None, a string, nor a
list/tuple of strings.
ValueError: If a key is empty, has an empty path segment, or
matches no subcomponent path or state entry.

### `getVelocity()`

```python Signature theme={null}
getVelocity() -> Optional[Velocity]
```

Return the latest body-frame linear velocity (m/s).

Angular velocity is available via `getIMU()` or `getState()`.

**Returns:**

Body-frame linear velocity, or `None` if no base-velocity
message has been received yet.

### `lieDown()`

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

Make the robot lie down.

### `moveByVelocity()`

```python Signature theme={null}
moveByVelocity(
    linear_velocity: Velocity,
    angular_velocity: Velocity,
    frame: str = 'body',
    *,
    duration: Optional[float] = 1.0,
) -> None
```

Command body-frame twist.

The command is republished at `_CMD_RATE_HZ` Hz until a new command
(including `stop`) is issued, or until *duration* seconds elapse —
Vision60's controller treats a gap as "stop", so continuous republish
is required to hold a velocity.

<ParamField body="linear_velocity" required>
  Body-frame linear velocity (m/s).
</ParamField>

<ParamField body="angular_velocity" required>
  Body-frame angular velocity (rad/s); only the z component is used for yaw.
</ParamField>

<ParamField body="frame" default="'body'">
  Reference frame. Only `"body"` is supported.
</ParamField>

<ParamField body="duration" default="1.0">
  Seconds to hold the command. Pass `None` to republish indefinitely until `stop()`.
</ParamField>

**Raises:**

NotImplementedError: If `frame == "world"` (matches Go2; world
frame is not supported on Vision60).
ValueError: If `frame` is any value other than `"body"` or
`"world"`.

### `setDefaultJointAngles()`

```python Signature theme={null}
setDefaultJointAngles(joint_pos: list) -> None
```

Set the default joint position for the robot.

<ParamField body="joint_pos" required>
  Value of the joint position.
</ParamField>

### `setDefaultJointVelocities()`

```python Signature theme={null}
setDefaultJointVelocities(joint_vel: list) -> None
```

Set the default joint velocity for the robot.

<ParamField body="joint_vel" required>
  Value of the joint velocity.
</ParamField>

### `standUp()`

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

Make the robot stand up.

### `stop()`

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

Halt all motion across this component's tree (soft e-stop).

Recursive walk owned by the base class: every subcomponent is
stopped first (children before their parent, leaf-to-root;
siblings in `subcomponents` insertion order), then this
component's own `_stop_self` hook runs. The walk is
best-effort — a failing component never prevents the rest of the
tree from being stopped; failures are collected and raised
together after the walk completes. Components (and their
subtrees) that have already been shut down are skipped. Safe to
call repeatedly: stopping an already-stopped tree re-runs the
hooks, which must tolerate that. Blocks until every hook has
returned.

Stops motion only; resources stay live and the component remains
usable — telemetry and every other public method keep working on a
stopped tree. Use `shutdown` to release resources. Stopping
re-arms each visited component, so a later `start` re-runs
the bring-up hooks — that is the stop-then-start restart path —
but it does not revoke callability: only `shutdown` does
that.

Subclasses must not replace this method — per-component stop
behavior belongs in `_stop_self`. An override may only
*extend* the walk (adding a driver-specific mode, as `UR5e` does
with its `immediate` escape hatch) and must delegate to
`super().stop()` for the normal path; it must never
re-implement the recursion.

**Raises:**

ComponentStopError: If one or more stop hooks raised. The
walk still visited every component; the exception carries
every `(component_path, exception)` pair.

## robot.front\_left and 4 more — camera

Reached as any of `robot.front_left`, `robot.front_right`, `robot.rear`, `robot.side_left`, `robot.side_right`; each is a `Vision60Camera` and its methods are `Vision60Camera`'s and run on the robot. Below, `<camera>` stands for any one of those names.

Camera sensor for the Vision60, bridging a ROS 2 `Image` topic to the

Methods inherited from the component base are shown in brief here; their full descriptions are under *Methods on the robot* above.

### `<camera>.cleanup()`

```python Signature theme={null}
<camera>.cleanup() -> None
```

Cleanup camera resources (no-op; shared node owned by caller).

### `<camera>.getCameraExtrinsics()`

```python Signature theme={null}
<camera>.getCameraExtrinsics() -> Optional[np.ndarray]
```

Get the extrinsic parameters for the camera.

### `<camera>.getCameraIntrinsics()`

```python Signature theme={null}
<camera>.getCameraIntrinsics() -> Optional[Tuple[float, float, float, float]]
```

Get the intrinsic parameters for the camera.

### `<camera>.getCameraSettings()`

```python Signature theme={null}
<camera>.getCameraSettings() -> CameraSettings
```

Get the camera settings.

### `<camera>.getData()`

```python Signature theme={null}
<camera>.getData() -> Image
```

Get the image from the camera.

### `<camera>.getImage()`

```python Signature theme={null}
<camera>.getImage() -> Optional[Image]
```

Read image from shared memory file path.

**Returns:**

The latest image as an `Image` object, or `None` if no
image message has been received yet.

### `<camera>.getState()`

```python Signature theme={null}
<camera>.getState(keys: Optional[Union[str, List[str]]] = None) -> Dict[str, Any]
```

Get a live state snapshot of this component's tree.

### `<camera>.recordCalibration()`

```python Signature theme={null}
<camera>.recordCalibration(calibration: dict) -> None
```

Install a recorded extrinsic calibration on this camera in place.

### `<camera>.reloadCalibration()`

```python Signature theme={null}
<camera>.reloadCalibration() -> dict
```

Re-read this camera's calibration from the robot's config and install it.

### `<camera>.setCameraExtrinsics()`

```python Signature theme={null}
<camera>.setCameraExtrinsics(transform: np.ndarray) -> None
```

Set the extrinsic parameters for the camera.

### `<camera>.setCameraIntrinsics()`

```python Signature theme={null}
<camera>.setCameraIntrinsics(fx: float, fy: float, cx: float, cy: float) -> None
```

Set the intrinsic parameters for the camera.

### `<camera>.setCameraSettings()`

```python Signature theme={null}
<camera>.setCameraSettings(settings: CameraSettings) -> None
```

Set the camera settings.

### `<camera>.stop()`

```python Signature theme={null}
<camera>.stop() -> None
```

Halt all motion across this component's tree (soft e-stop).

## robot.arm — arm

Reached as `robot.arm`; its methods are `Vision60Arm`'s and run on the robot.

Control the Ghost Robotics arm mounted on a Vision60 via ROS 2.

Methods inherited from the component base are shown in brief here; their full descriptions are under *Methods on the robot* above.

### `arm.addNamedPose()`

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

Define a pose\_name:joint\_angles pair in the dictionary of named poses

### `arm.ensureMode()`

```python Signature theme={null}
arm.ensureMode(
    field_name: str,
    value: int,
    *,
    n_tries: int = 50,
    wait_seconds: float = 0.1,
) -> None
```

Set a mode and confirm it via the `/state/heartbeat` echo.

Falls back to fire-and-forget when `ghost_manager_interfaces` is
not available or no heartbeat has been received yet.

<ParamField body="field_name" required>
  Mode field name (see `setMode`).
</ParamField>

<ParamField body="value" required>
  Desired value.
</ParamField>

<ParamField body="n_tries" default="50">
  Maximum publish-and-check attempts.
</ParamField>

<ParamField body="wait_seconds" default="0.1">
  Pause between attempts.
</ParamField>

**Raises:**

ValueError: If `field_name` is not a known Ghost mode field.
RuntimeError: If the heartbeat doesn't confirm the mode within
the retry budget.

### `arm.getEndEffectorPose()`

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

```text theme={null}
[Deprecated]
```

### `arm.getImage()`

```python Signature theme={null}
arm.getImage(camera_name: str = '', **kwargs) -> Image
```

Return the image of camera.

### `arm.getJointAngles()`

```python Signature theme={null}
arm.getJointAngles() -> List[float]
```

Get current arm joint angles, sliced from the body's `jointURDF`.

**Returns:**

Joint angles in radians (length `_NUM_JOINTS`).

**Raises:**

RuntimeError: If no `jointURDF` message has been received, or
the message doesn't contain enough joint values to slice.

### `arm.getJointVelocities()`

```python Signature theme={null}
arm.getJointVelocities() -> List[float]
```

Get current arm joint velocities, sliced from the body's `jointURDF`.

**Returns:**

Joint velocities in rad/s.

**Raises:**

RuntimeError: If no `jointURDF` message has been received, or
the velocity field is empty.

### `arm.getLidarPointCloud()`

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

Get a point cloud from the named LiDAR sensor.

### `arm.getNamedPose()`

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

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

### `arm.getOrientation()`

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

Return the EE orientation. Delegates to `getPose`.

**Raises:**

NotImplementedError: See `getPose`.

### `arm.getPosition()`

```python Signature theme={null}
arm.getPosition() -> Position
```

Return the EE position. Delegates to `getPose`.

**Raises:**

NotImplementedError: See `getPose`.

### `arm.getState()`

```python Signature theme={null}
arm.getState(keys: Optional[Union[str, List[str]]] = None) -> Dict[str, Any]
```

Get a live state snapshot of this component's tree.

### `arm.grasp()`

```python Signature theme={null}
arm.grasp() -> None
```

Close the gripper to `closed_position`.

### `arm.moveByVelocity()`

```python Signature theme={null}
arm.moveByVelocity(
    linear_velocity: Velocity,
    angular_velocity: Velocity,
    frame: str = 'body',
) -> None
```

Publish a single EE twist to `/mcu/command/arm/ee_twist`.

Ghost arm EE twist is expected to be republished by the caller at
high rate for sustained motion — this method publishes once and
returns.

<ParamField body="linear_velocity" required>
  Linear velocity in m/s.
</ParamField>

<ParamField body="angular_velocity" required>
  Angular velocity in rad/s.
</ParamField>

<ParamField body="frame" default="'body'">
  Reference frame is determined by the `ARM_C_B_FRAME` parameter on the robot. The argument is accepted for interface compatibility but does not change the frame.
</ParamField>

### `arm.moveToDeltaPose()`

```python Signature theme={null}
arm.moveToDeltaPose(delta_pose: Pose, blocking: bool = True) -> None
```

Offset the robot end effector by the specified delta pose from its current pose

### `arm.moveToHome()`

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

Move the arm to its predefined home pose.

### `arm.moveToNamedPose()`

```python Signature theme={null}
arm.moveToNamedPose(pose_name: str, blocking: bool = True) -> None
```

Move the robot to the joint angles of a named pose.

### `arm.moveToPose()`

```python Signature theme={null}
arm.moveToPose(
    pose: Pose,
    blocking: bool = True,
    *,
    moving_time: float = 2.0,
    publish_rate_hz: float = 100.0,
) -> None
```

Send an end-effector pose target to `/mcu/command/arm/ee_pose`.

The active EE frame (body vs. gripper) is determined by the
`ARM_C_B_FRAME` parameter on the robot. Set it via `setParam`
if you need to change frames.

<ParamField body="pose" required>
  Target EE pose (position in meters, orientation as a unit quaternion).
</ParamField>

<ParamField body="blocking" default="True">
  If True, republish for `moving_time` seconds at `publish_rate_hz`.
</ParamField>

<ParamField body="moving_time" default="2.0">
  Hold duration in seconds when blocking.
</ParamField>

<ParamField body="publish_rate_hz" default="100.0">
  Republish rate (the Ghost docs recommend 100 Hz for sustained pose commands).
</ParamField>

### `arm.release()`

```python Signature theme={null}
arm.release() -> None
```

Open the gripper to `open_position`.

### `arm.removeNamedPose()`

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

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

### `arm.setControlMode()`

```python Signature theme={null}
arm.setControlMode(value: int) -> None
```

Publish to `/command/setControlMode`.

Lower values have higher priority; the Ghost docs recommend
`140` for ROS 2 control and `180` for app/MAVLink.

### `arm.setGripperPosition()`

```python Signature theme={null}
arm.setGripperPosition(position: float) -> None
```

Publish a raw gripper position command (`Float32`).

### `arm.setGripperVelocity()`

```python Signature theme={null}
arm.setGripperVelocity(velocity: float) -> None
```

Publish a raw gripper velocity command (`Float32`).

### `arm.setJointAngles()`

```python Signature theme={null}
arm.setJointAngles(
    angles: List[float],
    blocking: bool = True,
    *,
    moving_time: Optional[float] = None,
    publish_rate_hz: float = 20.0,
) -> None
```

Publish target joint angles for the arm.

Joint position commands take precedence over joint velocity commands
on the Ghost arm, so only the `position` field of the `JointState`
message is set. Pass length `_NUM_JOINTS` to leave the gripper joint
held constant, or `_NUM_JOINTS + 1` to command the full arm.

<ParamField body="angles" required>
  Target joint angles in radians. Length must be `_NUM_JOINTS` or `_NUM_JOINTS + 1`.
</ParamField>

<ParamField body="blocking" default="True">
  If True, republish the command for `moving_time` seconds at `publish_rate_hz`. If False, publish once.
</ParamField>

<ParamField body="moving_time">
  Hold duration in seconds when blocking. Defaults to 2.0 seconds when blocking and unset.
</ParamField>

<ParamField body="publish_rate_hz" default="20.0">
  Republish rate while blocking.
</ParamField>

**Raises:**

ValueError: If `angles` does not have length `_NUM_JOINTS` or
`_NUM_JOINTS + 1`.

### `arm.setJointVelocities()`

```python Signature theme={null}
arm.setJointVelocities(
    velocities: list,
    *,
    duration: float = 1.0,
    publish_rate_hz: float = 20.0,
) -> None
```

Publish target joint velocities for the arm.

<ParamField body="velocities" required>
  Target joint velocities in rad/s. Length must be `_NUM_JOINTS` or `_NUM_JOINTS + 1`.
</ParamField>

<ParamField body="duration" default="1.0">
  Seconds to republish the command.
</ParamField>

<ParamField body="publish_rate_hz" default="20.0">
  Republish rate in Hz.
</ParamField>

**Raises:**

ValueError: If `velocities` does not have length `_NUM_JOINTS`
or `_NUM_JOINTS + 1`.

### `arm.setMode()`

```python Signature theme={null}
arm.setMode(field_name: str, value: int) -> None
```

Publish a `robotMode` command (fire-and-forget).

Use `ensureMode` for confirmed sets.

<ParamField body="field_name" required>
  Mode field name (e.g. `"arm"`, `"action"`, `"vision_mode"`).
</ParamField>

<ParamField body="value" required>
  Desired value for that field.
</ParamField>

**Raises:**

ValueError: If `field_name` is not a known Ghost mode field.

### `arm.setParam()`

```python Signature theme={null}
arm.setParam(
    name: str,
    val: list,
    *,
    planner: bool = False,
    n_tries: int = 10,
    wait_seconds: float = 0.05,
) -> None
```

Set a robot or planner parameter via `/mcu/command/param`.

Confirmed by the matching `/mcu/state/param` echo.

<ParamField body="name" required>
  Parameter name (e.g. `"ARM_PREDEF_CFG"`, `"ARM_PAYLOAD"`).
</ParamField>

<ParamField body="val" required>
  Parameter value as a list of floats.
</ParamField>

<ParamField body="planner" default="False">
  True for planner parameters, False for robot parameters.
</ParamField>

<ParamField body="n_tries" default="10">
  Maximum publish-and-check attempts.
</ParamField>

<ParamField body="wait_seconds" default="0.05">
  Pause between attempts.
</ParamField>

**Raises:**

RuntimeError: If `ghost_manager_interfaces` is not installed,
or the parameter set is not confirmed within the retry budget.

### `arm.setPredefinedConfig()`

```python Signature theme={null}
arm.setPredefinedConfig(config_id: int) -> None
```

Send the arm to a predefined configuration via `ARM_PREDEF_CFG`.

Valid values per the Ghost low-level parameters doc are `0` (None)
and `1..8` (predefined configs). The robot resets the parameter
automatically once the arm reaches or fails the requested config.

<ParamField body="config_id" required>
  Predefined config id in `[0, 8]`.
</ParamField>

**Raises:**

ValueError: If `config_id` is outside the range `[0, 8]`.
RuntimeError: If `ghost_manager_interfaces` is not available
or the parameter set is not confirmed within the retry budget.

### `arm.stop()`

```python Signature theme={null}
arm.stop() -> None
```

Halt all motion across this component's tree (soft e-stop).

### `arm.stow()`

```python Signature theme={null}
arm.stow() -> None
```

Stow the arm to its rest configuration.

**Raises:**

RuntimeError: If the heartbeat doesn't confirm `arm_fsm == 0`
within the retry budget.

### `arm.unstow()`

```python Signature theme={null}
arm.unstow() -> None
```

Unstow the arm so it accepts motion commands.

**Raises:**

RuntimeError: If the heartbeat doesn't confirm `arm_fsm == 1`
within the retry budget (only checked when
`ghost_manager_interfaces` is available).

### `arm.validateGrasp()`

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

Check whether the end effector is currently holding an object.

## robot.vision60\_lidar — lidar

Reached as `robot.vision60_lidar`; its methods are `Vision60Lidar`'s and run on the robot.

LiDAR sensor for the Vision60, bridging a ROS 2 `PointCloud2` topic.

Methods inherited from the component base are shown in brief here; their full descriptions are under *Methods on the robot* above.

### `vision60_lidar.cleanup()`

```python Signature theme={null}
vision60_lidar.cleanup() -> None
```

Cleanup lidar resources (no-op; shared node owned by caller).

### `vision60_lidar.getData()`

```python Signature theme={null}
vision60_lidar.getData() -> PointCloud
```

### `vision60_lidar.getPointCloud()`

```python Signature theme={null}
vision60_lidar.getPointCloud() -> Optional[PointCloud]
```

Return the most recently received point cloud, or `None`.

### `vision60_lidar.getState()`

```python Signature theme={null}
vision60_lidar.getState(keys: Optional[Union[str, List[str]]] = None) -> Dict[str, Any]
```

Get a live state snapshot of this component's tree.

### `vision60_lidar.stop()`

```python Signature theme={null}
vision60_lidar.stop() -> None
```

Halt all motion across this component's tree (soft e-stop).

## Not implemented on this robot

Declared by the interface, raises `NotImplementedError` here: `getJointAngles`, `getJointStates`, `setJointAngles`, `arm.endFreeDrive`, `arm.followJointTrajectory`, `arm.getPose`, `arm.startFreeDrive`.

## Lifecycle and configuration

The driver's own bring-up and configuration hooks. The edge runs them when the robot comes up; do not call them from a program. Note that `robot.shutdown()` on the proxy is not the method below — it is `RemoteRobot.shutdown()`, which closes your connection and leaves the robot as it was.

* `addSensor()` — Add an external sensor to the robot.
* `addSubcomponent()` — Attach a child component under a name.
* `builtin_subcomponents()` — Declare the five on-board cameras the Vision60 always ships with.
* `configHash()` — Hash this component's serialized config subtree.
* `config_schema()`
* `from_config()` — Construct this component and its config-declared subtree.
* `getIdentity()` — Get this component's own hardware identity (serial, model, version, MAC).
* `getRobotId()` — Stable, readable identifier for a robot or rig, for a database key.
* `serialize()` — Serialize this component tree back to its config envelope.
* `setup_shutdown_handlers()` — Register the process-wide atexit and signal handlers for safe teardown.
* `shutdown()` — Shut down this component's tree, halting motion and releasing resources.
* `start()` — Bring this component's tree online (connect, enable, arm).

The contract these methods implement is **Robot interface**; values returned are **grid-types** (camera reads return `Image` — call [`decode()`](/python-api/grid-types/image) for an ndarray). You reach the robot through [`connect`](/python-api/grid-nexus-client/connect).


## Related topics

- [Arm](/python-api/robot-interface/arm.md)
- [EndEffector](/python-api/robot-interface/endeffector.md)
- [The Intelligence Grid for Physical AI](/introduction.md)
- [grid-cortex-client](/python-api/grid-cortex-client/overview.md)
- [ROS2 Communication](/simulation/isaac/comms.md)
