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

# Galaxea R1 Pro Mobile Manipulator

> The Galaxea R1 Pro Mobile Manipulator as GRID drives it

The Galaxea R1 Pro Mobile Manipulator 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 `GalaxeaR1Pro`. 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("<r1pro-name>")

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

## Methods on the robot

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

### `addNamedPose()`

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

Register a named pose, replacing any entry of the same name.

<ParamField body="pose_name" required>
  Case-insensitive name to register the pose under.
</ParamField>

<ParamField body="joint_angles" required>
  Joint angles in radians per joint group (`"left_arm"`, `"right_arm"`, `"base"`); a group may be omitted to leave that group where it is.
</ParamField>

**Raises:**

ValueError: If `joint_angles` names a group this robot does not have.

### `getBatteryState()`

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

Get battery state (voltage, current, capacity). Delegates to `GalaxeaR1ProBase`.

### `getIMU()`

```python Signature theme={null}
getIMU(sensor: str = 'chassis') -> dict
```

Get IMU data for `"chassis"` or `"torso"`. Delegates to `GalaxeaR1ProBase`.

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

### `getJointAngles()`

```python Signature theme={null}
getJointAngles(
    group: Optional[str] = None,
) -> Union[Dict[str, List[float]], List[float]]
```

Get joint angles.

<ParamField body="group">
  If provided, return joint angles for that subcomponent only (as a flat `list[float]`). If `None` (default), return a dict mapping every subcomponent name to its joint angles.
</ParamField>

**Returns:**

`list[float]` when *group* is given, otherwise
`dict[str, list[float]]`.

**Raises:**

KeyError: If *group* is not a known subcomponent.

````python theme={null}
```python
# All groups at once
all_joints = robot.getJointAngles()
# -> {"left_arm": [...], "right_arm": [...], "base": [...]}

# Single group (same return type as Arm.getJointAngles())
left_joints = robot.getJointAngles("left_arm")
# -> [0.0, 0.1, ...]
````

````

### `getLidarPointCloud()`

```python Signature
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() -> Orientation
```

Get the chassis orientation in world frame.

Chassis orientation is calculated from accumulated LiDAR-IMU odometry,
with the origin at the robot's initial orientation on startup.
Delegates to `GalaxeaR1ProBase`.

**Raises:**

RuntimeError: If no odometry data has been received yet.

### `getPosition()`

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

Get the chassis position in world frame.

Chassis position is calculated from accumulated LiDAR-IMU odometry,
with the origin at the robot's initial position on startup.
Delegates to `GalaxeaR1ProBase`.

**Raises:**

RuntimeError: If no odometry data 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.

### `moveByVelocity()`

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

Command chassis velocity.

Delegates to `GalaxeaR1ProBase.moveByVelocity`. The velocity is
republished at 50 Hz until `stop` is called, or until *duration*
seconds have elapsed.

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

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

<ParamField body="frame" default="'body'">
  Reference frame for the velocity. Only `"body"` is supported; any other value (including `"world"`) raises.
</ParamField>

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

**Raises:**

ValueError: If *frame* is not `"body"`.

### `moveToNamedPose()`

```python Signature theme={null}
moveToNamedPose(pose_name: str) -> None
```

Move arms and torso to a named pose.

Available poses are stored in `named_poses`. Built-in poses:

* `"home"` -- upright with elbows bent 90°.
* `"rest"` -- upright with arms straight (all joints zero).
* `"sleep"` -- torso folded down, elbows bent.

<ParamField body="pose_name" required>
  Case-insensitive pose name (e.g. `"home"`, `"sleep"`).
</ParamField>

**Raises:**

ValueError: If the pose name is not recognised.

### `moveToPose()`

```python Signature theme={null}
moveToPose(
    pose: Pose,
    blocking: bool = True,
    *,
    frame: str = 'world',
    pos_threshold: float = 0.05,
    yaw_threshold: float = 0.05,
    max_linear_speed: float = 0.5,
    max_angular_speed: float = 1.0,
    kp_linear: float = 1.0,
    ki_linear: float = 0.1,
    kp_angular: float = 2.0,
    ki_angular: float = 0.2,
    integral_fraction: float = 0.2,
    timeout: float = 30.0,
) -> None
```

Drive the chassis to a target pose.

Delegates to `GalaxeaR1ProBase.moveToPose`. See that method for
full documentation of the PI controller and its parameters.

!!! note
The world frame origin is the robot's position and heading at
startup.  When *frame* is `"world"`, coordinates are absolute
in that odometry frame.  When *frame* is `"body"`, the target
pose is interpreted as a delta relative to the current pose at
the time of the call.

<ParamField body="pose" required>
  Target pose. Only `position.x`, `position.y`, and the yaw component (rotation about Z) of `orientation` are used; `z`, roll, and pitch are ignored. Interpretation depends on *frame*: absolute world-frame coordinates when `"world"`, or a body-frame delta (dx forward, dy left, dyaw) when `"body"`.
</ParamField>

<ParamField body="blocking" default="True">
  This move always blocks until convergence or timeout; passing `blocking=False` logs a warning. Defaults to True.
</ParamField>

<ParamField body="frame" default="'world'">
  Reference frame for the target — `"world"` (default) for an absolute pose, or `"body"` for a delta relative to the current pose.
</ParamField>

<ParamField body="pos_threshold" default="0.05">
  Position convergence threshold in meters.
</ParamField>

<ParamField body="yaw_threshold" default="0.05">
  Yaw convergence threshold in radians.
</ParamField>

<ParamField body="max_linear_speed" default="0.5">
  Maximum linear velocity magnitude in m/s.
</ParamField>

<ParamField body="max_angular_speed" default="1.0">
  Maximum angular velocity magnitude in rad/s.
</ParamField>

<ParamField body="kp_linear" default="1.0">
  Proportional gain for XY position error.
</ParamField>

<ParamField body="ki_linear" default="0.1">
  Integral gain for XY position error.
</ParamField>

<ParamField body="kp_angular" default="2.0">
  Proportional gain for yaw error.
</ParamField>

<ParamField body="ki_angular" default="0.2">
  Integral gain for yaw error.
</ParamField>

<ParamField body="integral_fraction" default="0.2">
  Maximum fraction of max speed that the integral term can contribute (0.0 to 1.0). Limits windup so the integral handles steady-state error without causing overshoot on longer drives.
</ParamField>

<ParamField body="timeout" default="30.0">
  Maximum time in seconds before the controller gives up.
</ParamField>

**Raises:**

ValueError: If *frame* is not `"world"` or `"body"`.
RuntimeError: If no odometry data is available, or if *timeout*
is exceeded before convergence.

### `setBrakeMode()`

```python Signature theme={null}
setBrakeMode(engaged: bool) -> None
```

Engage or disengage the chassis brake. Delegates to `GalaxeaR1ProBase`.

### `setJointAngles()`

```python Signature theme={null}
setJointAngles(
    angles: Union[Dict[str, list], list],
    velocities: Union[Optional[Dict[str, list]], list] = None,
    group: Optional[str] = None,
) -> None
```

Set joint angles.

Can be called in two ways:

* **Multi-group** (default): pass a dict mapping group names to
  angle lists.  `velocities` may also be a dict.
* **Single-group**: pass a flat `list` of angles together with
  `group="&lt;name>"`.  `velocities` may also be a flat list.
  This matches the `Arm` / `Humanoid` / `Quadruped`
  signature.

<ParamField body="angles" required>
  Target joint angles in radians — a dict for multi-group or a list for single-group.
</ParamField>

<ParamField body="velocities">
  Optional joint velocities. In single-group mode, a list or scalar. In multi-group mode, a dict mapping group names to velocity lists/scalars (partial dicts OK — omitted groups get no velocity), a single scalar (broadcast to every group being commanded), or `None`.
</ParamField>

<ParamField body="group">
  Subcomponent name.  Required when *angles* is a list.
</ParamField>

**Raises:**

KeyError: If a group name is not a known subcomponent.
TypeError: If *angles* is a list but *group* is not provided,
or if *velocities* is a list in multi-group mode.

````python theme={null}
```python
# Multi-group
robot.setJointAngles({"left_arm": angles_l, "base": angles_b})

# Multi-group with per-group velocities
robot.setJointAngles(
    {"left_arm": angles_l, "right_arm": angles_r},
    velocities={"left_arm": 0.5},  # only left_arm; right_arm uses default
)

# Per-group velocities as a list
robot.setJointAngles(
    {"left_arm": angles_l, "right_arm": angles_r},
    velocities={"left_arm": [0.5] * 7, "right_arm": [0.1] * 7},
)

# Multi-group with a single velocity for all groups/joints
robot.setJointAngles(
    {"left_arm": angles_l, "base": angles_b},
    velocities=0.5,
)

# Single-group (same list signature as Arm, Humanoid, etc.)
robot.setJointAngles(angles_l, group="left_arm")
````

````

### `stop()`

```python Signature
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.

## Properties on the robot

Read as `robot.<property>`; each read runs the getter on the robot.

<ResponseField name="named_poses" type="Dict[str, Dict[str, List[float]]]">
  Registered poses as `&#123;name: &#123;joint group: angles in radians&#125;&#125;` (a copy).

  Mutating the returned mapping does not change what the robot knows:
  register entries with `addNamedPose`, or assign a whole mapping
  to replace them all.
</ResponseField>

## robot.head\_camera\_left and 10 more — camera

Reached as any of `robot.head_camera_left`, `robot.head_camera_right`, `robot.wrist_left`, `robot.wrist_right`, `robot.chassis_front_left`, `robot.chassis_front_right`, `robot.chassis_left`, `robot.chassis_right`, `robot.chassis_rear`, `robot.wrist_left_depth`, `robot.wrist_right_depth`; each is a `R1ProCamera` and its methods are `R1ProCamera`'s and run on the robot. Below, `<camera>` stands for any one of those names.

Camera sensor bridging a ROS 2 image topic to the GRID `Camera` interface.

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

### `<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(*, compressed: bool = True) -> Optional[Image]
```

Return the latest image, or `None` if no message has arrived yet.

ROS `CompressedImage` topics already carry JPEG/PNG bytes. By
default we pass those through unchanged (\~30x bandwidth saving
over decoding to an ndarray here); pass `compressed=False` to
get a decoded RGB ndarray instead. Unknown compressed formats
always fall back to the OpenCV decode path. Raw depth messages
(`32FC1`, `16UC1`) are converted to numpy arrays — the
`compressed` flag has no effect on depth.

<ParamField body="compressed" type="bool, optional" default="True">
  when True (default) and the ROS message is a JPEG/PNG CompressedImage, return the bytes via `Image(..., encoding_format=...)`. When False, always decode to an RGB ndarray.
</ParamField>

### `<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.left\_arm — arm

Reached as `robot.left_arm`; its methods are `GalaxeaR1ProArm`'s and run on the robot.

Control one 7-DOF arm of the Galaxea R1Pro via ROS 2.

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

### `left_arm.addNamedPose()`

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

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

### `left_arm.getEndEffectorPose()`

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

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

### `left_arm.getGripperPosition()`

```python Signature theme={null}
left_arm.getGripperPosition() -> float
```

Get the current gripper position.

**Returns:**

Gripper position where `0` is fully closed and `100` is fully
open.

**Raises:**

RuntimeError: If no gripper feedback has been received yet.

### `left_arm.getImage()`

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

Return the image of camera.

### `left_arm.getJointAngles()`

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

Get current joint angles for all 7 arm joints.

**Returns:**

Joint angles in radians, ordered `joint1` through `joint7`.

**Raises:**

RuntimeError: If no arm joint state feedback has been received yet.

### `left_arm.getLidarPointCloud()`

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

Get a point cloud from the named LiDAR sensor.

### `left_arm.getNamedPose()`

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

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

### `left_arm.getOrientation()`

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

Get the end-effector orientation (delegates to `getPose`).

### `left_arm.getPose()`

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

Get the current end-effector pose.

**Returns:**

The end-effector pose in the `torso_link4` frame (+X
forward, +Y left, +Z up). Returns an identity pose
(origin, no rotation) if no feedback has been received
yet.

.. note::
The orientation quaternion represents the rotation of the
`gripper_link` frame relative to `torso_link4`.  The
`gripper_link` axes are fixed to the gripper body:

* **+X** — up the wrist (toward the wrist camera)
* **+Y** — left across the gripper plane
* **+Z** — out through the back of the gripper (opposite the
  opening)

At identity `(0, 0, 0, 1)` the two frames are aligned, so
gripper +Z (out the back) coincides with torso +Z (up),
meaning the gripper opening faces **straight down**.  This
corresponds to the arms hanging relaxed at the robot's sides.

At the **home** pose the orientation is approximately
`(0, -0.71, 0, 0.71)` (-90° pitch about Y), which rotates
the gripper opening to face **forward** (+X in torso\_link4).

The feedback frame is decided by the vendor stack installed on
the unit: legacy stacks report in `torso_link4`, newer Galaxea
(MOCA-generation) stacks report in `base_link`. Feedback whose
`frame_id` is neither empty nor `torso_link4` is re-expressed
into `torso_link4` through a live tf2 lookup before being
returned, so the returned pose is always `torso_link4`
regardless of the unit's stack generation.

**Raises:**

RuntimeError: If feedback reports a frame other than
`torso_link4` and no transform into `torso_link4` is
available on `/tf` to re-express it — returning the raw
numbers would silently mis-place the end effector by the
(posture-dependent) offset between the two frames.

### `left_arm.getPosition()`

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

Get the end-effector position (delegates to `getPose`).

### `left_arm.getState()`

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

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

### `left_arm.grasp()`

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

Close the gripper to `closed_position`.

### `left_arm.moveToDeltaPose()`

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

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

### `left_arm.moveToHome()`

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

Move the arm to its predefined home pose.

### `left_arm.moveToNamedPose()`

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

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

### `left_arm.moveToPose()`

```python Signature theme={null}
left_arm.moveToPose(
    pose: Pose,
    blocking: bool = True,
    *,
    moving_time: float = 2.0,
    accel_time: float = 0.5,
    max_pos_step: float = 0.02,
    max_ori_step_deg: float = 5.0,
    pos_threshold: float = 0.01,
    ori_threshold_deg: float = 3.0,
    step_timeout: float = 0.3,
    timeout: float = 10.0,
) -> None
```

Command the arm to a Cartesian pose via interpolated steps.

Breaks the movement into small steps (linear position interpolation,
spherical orientation interpolation) and waits for the IK solver to
converge at each step before advancing.  This compensates for the
relaxed IK solver's tendency to undershoot on large displacements.

The pose is an absolute transform of `gripper_link` expressed
in the `torso_link4` frame (the pelvis / top of the torso
linkage).

The `torso_link4` coordinate frame follows the convention:

* **+X** = forward (away from the robot's chest)
* **+Y** = left (from the robot's perspective)
* **+Z** = up

The orientation quaternion represents the rotation of the
`gripper_link` frame relative to `torso_link4`.  The
`gripper_link` axes are fixed to the gripper body:

* **+X** — up the wrist (toward the wrist camera)
* **+Y** — left across the gripper plane
* **+Z** — out through the back of the gripper (opposite the
  opening)

At identity `(0, 0, 0, 1)` the two frames are aligned, so
gripper +Z (out the back) coincides with torso +Z (up),
meaning the gripper opening faces **straight down**.  This
corresponds to the arms hanging relaxed at the robot's sides.

At the **home** pose the orientation is approximately
`(0, -0.71, 0, 0.71)` (-90° pitch about Y), which rotates
the gripper opening to face **forward** (+X in torso\_link4).

At rest the left gripper is at roughly
`(0.0, +0.25, -0.43)` and the right at `(0.0, -0.25, -0.43)`.
At home, roughly `(0.42, +0.25, -0.01)` and
`(0.42, -0.25, -0.01)`.

!!! note
Requires the relaxed IK nodes to be running
(`r1_pro_left_arm_relaxed_ik_launch.py` /
`r1_pro_right_arm_relaxed_ik_launch.py`). Without them
the command topic has no subscribers and nothing will happen.
See `r1pro-ik.service` for an auto-start systemd unit.

<ParamField body="pose" required>
  Absolute target pose (position in meters, orientation as a quaternion `(x, y, z, w)`) in the `torso_link4` frame.
</ParamField>

<ParamField body="blocking" default="True">
  This move always blocks until convergence or timeout; passing `blocking=False` logs a warning. Defaults to True.
</ParamField>

<ParamField body="moving_time" default="2.0">
  Unused -- accepted for interface compatibility.
</ParamField>

<ParamField body="accel_time" default="0.5">
  Unused -- accepted for interface compatibility.
</ParamField>

<ParamField body="max_pos_step" default="0.02">
  Maximum position displacement per interpolation step in meters.
</ParamField>

<ParamField body="max_ori_step_deg" default="5.0">
  Maximum orientation displacement per step in degrees.
</ParamField>

<ParamField body="pos_threshold" default="0.01">
  Position convergence threshold in meters. The step is considered reached when the EE is within this distance of the target.
</ParamField>

<ParamField body="ori_threshold_deg" default="3.0">
  Orientation convergence threshold in degrees (geodesic quaternion distance).
</ParamField>

<ParamField body="step_timeout" default="0.3">
  Maximum seconds to wait for convergence at each interpolation step before advancing.  If an intermediate step times out, a warning is logged and the next step is attempted (the IK solver may still converge from the nearby pose).
</ParamField>

<ParamField body="timeout" default="10.0">
  Maximum total seconds for the entire motion.
</ParamField>

**Raises:**

RuntimeError: If the overall `timeout` is exceeded, or if
the final interpolation step does not converge within
`step_timeout` — in either case the arm will be
somewhere along the interpolated path but not at the
requested target. Also raised before any motion if EE
feedback reports a frame other than `torso_link4` that
cannot be re-expressed via tf2 (no `/tf` transform
available): commanding interpolated targets computed
from a mis-framed current pose would move the arm to
unintended positions.

### `left_arm.release()`

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

Open the gripper to `open_position`.

### `left_arm.removeNamedPose()`

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

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

### `left_arm.setGripperPosition()`

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

Set the gripper position.

<ParamField body="position" required>
  Target position in the range `[0, 100]` where `0` is fully closed and `100` is fully open.
</ParamField>

### `left_arm.setJointAngles()`

```python Signature theme={null}
left_arm.setJointAngles(
    angles: list,
    blocking: bool = False,
    *,
    moving_time: float = 2.0,
    accel_time: float = 0.5,
    velocities: list = None,
) -> None
```

Publish target joint angles for the arm.

<ParamField body="angles" required>
  Target joint angles in radians. A scalar is broadcast to all 7 joints; a list or `np.ndarray` must have length 7.
</ParamField>

<ParamField body="blocking" default="False">
  Not honored. This method publishes the target and returns immediately; passing `blocking=True` logs a warning. The Galaxea controller handles trajectory timing. Defaults to False.
</ParamField>

<ParamField body="moving_time" default="2.0">
  Unused -- accepted for interface compatibility.
</ParamField>

<ParamField body="accel_time" default="0.5">
  Unused -- accepted for interface compatibility.
</ParamField>

<ParamField body="velocities">
  Optional joint velocities in rad/s. A scalar is broadcast to all 7 joints. !!! note `blocking`, `moving_time`, and `accel_time` are accepted for compatibility with the base `Arm` interface but have no effect. The Galaxea motion controller handles trajectory timing internally.
</ParamField>

### `left_arm.stop()`

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

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

### `left_arm.validateGrasp()`

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

Check whether the end effector is currently holding an object.

## robot.right\_arm — arm

Reached as `robot.right_arm`; its methods are `GalaxeaR1ProArm`'s and run on the robot.

Control one 7-DOF arm of the Galaxea R1Pro via ROS 2.

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

### `right_arm.addNamedPose()`

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

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

### `right_arm.getEndEffectorPose()`

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

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

### `right_arm.getGripperPosition()`

```python Signature theme={null}
right_arm.getGripperPosition() -> float
```

Get the current gripper position.

**Returns:**

Gripper position where `0` is fully closed and `100` is fully
open.

**Raises:**

RuntimeError: If no gripper feedback has been received yet.

### `right_arm.getImage()`

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

Return the image of camera.

### `right_arm.getJointAngles()`

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

Get current joint angles for all 7 arm joints.

**Returns:**

Joint angles in radians, ordered `joint1` through `joint7`.

**Raises:**

RuntimeError: If no arm joint state feedback has been received yet.

### `right_arm.getLidarPointCloud()`

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

Get a point cloud from the named LiDAR sensor.

### `right_arm.getNamedPose()`

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

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

### `right_arm.getOrientation()`

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

Get the end-effector orientation (delegates to `getPose`).

### `right_arm.getPose()`

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

Get the current end-effector pose.

**Returns:**

The end-effector pose in the `torso_link4` frame (+X
forward, +Y left, +Z up). Returns an identity pose
(origin, no rotation) if no feedback has been received
yet.

.. note::
The orientation quaternion represents the rotation of the
`gripper_link` frame relative to `torso_link4`.  The
`gripper_link` axes are fixed to the gripper body:

* **+X** — up the wrist (toward the wrist camera)
* **+Y** — left across the gripper plane
* **+Z** — out through the back of the gripper (opposite the
  opening)

At identity `(0, 0, 0, 1)` the two frames are aligned, so
gripper +Z (out the back) coincides with torso +Z (up),
meaning the gripper opening faces **straight down**.  This
corresponds to the arms hanging relaxed at the robot's sides.

At the **home** pose the orientation is approximately
`(0, -0.71, 0, 0.71)` (-90° pitch about Y), which rotates
the gripper opening to face **forward** (+X in torso\_link4).

The feedback frame is decided by the vendor stack installed on
the unit: legacy stacks report in `torso_link4`, newer Galaxea
(MOCA-generation) stacks report in `base_link`. Feedback whose
`frame_id` is neither empty nor `torso_link4` is re-expressed
into `torso_link4` through a live tf2 lookup before being
returned, so the returned pose is always `torso_link4`
regardless of the unit's stack generation.

**Raises:**

RuntimeError: If feedback reports a frame other than
`torso_link4` and no transform into `torso_link4` is
available on `/tf` to re-express it — returning the raw
numbers would silently mis-place the end effector by the
(posture-dependent) offset between the two frames.

### `right_arm.getPosition()`

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

Get the end-effector position (delegates to `getPose`).

### `right_arm.getState()`

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

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

### `right_arm.grasp()`

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

Close the gripper to `closed_position`.

### `right_arm.moveToDeltaPose()`

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

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

### `right_arm.moveToHome()`

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

Move the arm to its predefined home pose.

### `right_arm.moveToNamedPose()`

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

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

### `right_arm.moveToPose()`

```python Signature theme={null}
right_arm.moveToPose(
    pose: Pose,
    blocking: bool = True,
    *,
    moving_time: float = 2.0,
    accel_time: float = 0.5,
    max_pos_step: float = 0.02,
    max_ori_step_deg: float = 5.0,
    pos_threshold: float = 0.01,
    ori_threshold_deg: float = 3.0,
    step_timeout: float = 0.3,
    timeout: float = 10.0,
) -> None
```

Command the arm to a Cartesian pose via interpolated steps.

Breaks the movement into small steps (linear position interpolation,
spherical orientation interpolation) and waits for the IK solver to
converge at each step before advancing.  This compensates for the
relaxed IK solver's tendency to undershoot on large displacements.

The pose is an absolute transform of `gripper_link` expressed
in the `torso_link4` frame (the pelvis / top of the torso
linkage).

The `torso_link4` coordinate frame follows the convention:

* **+X** = forward (away from the robot's chest)
* **+Y** = left (from the robot's perspective)
* **+Z** = up

The orientation quaternion represents the rotation of the
`gripper_link` frame relative to `torso_link4`.  The
`gripper_link` axes are fixed to the gripper body:

* **+X** — up the wrist (toward the wrist camera)
* **+Y** — left across the gripper plane
* **+Z** — out through the back of the gripper (opposite the
  opening)

At identity `(0, 0, 0, 1)` the two frames are aligned, so
gripper +Z (out the back) coincides with torso +Z (up),
meaning the gripper opening faces **straight down**.  This
corresponds to the arms hanging relaxed at the robot's sides.

At the **home** pose the orientation is approximately
`(0, -0.71, 0, 0.71)` (-90° pitch about Y), which rotates
the gripper opening to face **forward** (+X in torso\_link4).

At rest the left gripper is at roughly
`(0.0, +0.25, -0.43)` and the right at `(0.0, -0.25, -0.43)`.
At home, roughly `(0.42, +0.25, -0.01)` and
`(0.42, -0.25, -0.01)`.

!!! note
Requires the relaxed IK nodes to be running
(`r1_pro_left_arm_relaxed_ik_launch.py` /
`r1_pro_right_arm_relaxed_ik_launch.py`). Without them
the command topic has no subscribers and nothing will happen.
See `r1pro-ik.service` for an auto-start systemd unit.

<ParamField body="pose" required>
  Absolute target pose (position in meters, orientation as a quaternion `(x, y, z, w)`) in the `torso_link4` frame.
</ParamField>

<ParamField body="blocking" default="True">
  This move always blocks until convergence or timeout; passing `blocking=False` logs a warning. Defaults to True.
</ParamField>

<ParamField body="moving_time" default="2.0">
  Unused -- accepted for interface compatibility.
</ParamField>

<ParamField body="accel_time" default="0.5">
  Unused -- accepted for interface compatibility.
</ParamField>

<ParamField body="max_pos_step" default="0.02">
  Maximum position displacement per interpolation step in meters.
</ParamField>

<ParamField body="max_ori_step_deg" default="5.0">
  Maximum orientation displacement per step in degrees.
</ParamField>

<ParamField body="pos_threshold" default="0.01">
  Position convergence threshold in meters. The step is considered reached when the EE is within this distance of the target.
</ParamField>

<ParamField body="ori_threshold_deg" default="3.0">
  Orientation convergence threshold in degrees (geodesic quaternion distance).
</ParamField>

<ParamField body="step_timeout" default="0.3">
  Maximum seconds to wait for convergence at each interpolation step before advancing.  If an intermediate step times out, a warning is logged and the next step is attempted (the IK solver may still converge from the nearby pose).
</ParamField>

<ParamField body="timeout" default="10.0">
  Maximum total seconds for the entire motion.
</ParamField>

**Raises:**

RuntimeError: If the overall `timeout` is exceeded, or if
the final interpolation step does not converge within
`step_timeout` — in either case the arm will be
somewhere along the interpolated path but not at the
requested target. Also raised before any motion if EE
feedback reports a frame other than `torso_link4` that
cannot be re-expressed via tf2 (no `/tf` transform
available): commanding interpolated targets computed
from a mis-framed current pose would move the arm to
unintended positions.

### `right_arm.release()`

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

Open the gripper to `open_position`.

### `right_arm.removeNamedPose()`

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

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

### `right_arm.setGripperPosition()`

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

Set the gripper position.

<ParamField body="position" required>
  Target position in the range `[0, 100]` where `0` is fully closed and `100` is fully open.
</ParamField>

### `right_arm.setJointAngles()`

```python Signature theme={null}
right_arm.setJointAngles(
    angles: list,
    blocking: bool = False,
    *,
    moving_time: float = 2.0,
    accel_time: float = 0.5,
    velocities: list = None,
) -> None
```

Publish target joint angles for the arm.

<ParamField body="angles" required>
  Target joint angles in radians. A scalar is broadcast to all 7 joints; a list or `np.ndarray` must have length 7.
</ParamField>

<ParamField body="blocking" default="False">
  Not honored. This method publishes the target and returns immediately; passing `blocking=True` logs a warning. The Galaxea controller handles trajectory timing. Defaults to False.
</ParamField>

<ParamField body="moving_time" default="2.0">
  Unused -- accepted for interface compatibility.
</ParamField>

<ParamField body="accel_time" default="0.5">
  Unused -- accepted for interface compatibility.
</ParamField>

<ParamField body="velocities">
  Optional joint velocities in rad/s. A scalar is broadcast to all 7 joints. !!! note `blocking`, `moving_time`, and `accel_time` are accepted for compatibility with the base `Arm` interface but have no effect. The Galaxea motion controller handles trajectory timing internally.
</ParamField>

### `right_arm.stop()`

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

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

### `right_arm.validateGrasp()`

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

Check whether the end effector is currently holding an object.

## robot.base — mobile base

Reached as `robot.base`; its methods are `GalaxeaR1ProBase`'s and run on the robot.

Control the Galaxea R1Pro chassis and 4-DOF torso via ROS 2.

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

### `base.getBatteryState()`

```python Signature theme={null}
base.getBatteryState() -> dict
```

Get battery state from the BMS.

**Returns:**

A dict with keys `"voltage"` (V), `"current"` (A), and
`"capacity"` (%). Returns zeros if the BMS topic is
unavailable or no message has been received yet.

### `base.getIMU()`

```python Signature theme={null}
base.getIMU(sensor: str = 'chassis') -> dict
```

Get IMU data from the chassis or torso IMU.

<ParamField body="sensor" default="'chassis'">
  `"chassis"` or `"torso"`.
</ParamField>

**Returns:**

A dict with keys `"linear_acceleration"`, `"angular_velocity"`,
and `"orientation"`, each containing `x`, `y`, `z` (and `w` for
orientation) float values. Returns zeros / identity if no
feedback has been received yet.

**Raises:**

ValueError: If *sensor* is not `"chassis"` or `"torso"`.

### `base.getImage()`

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

Return the image of camera.

### `base.getJointAngles()`

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

Get current joint angles for the 4-DOF torso linkage.

**Returns:**

Joint angles in radians.

**Raises:**

RuntimeError: If no torso joint state feedback has been received yet.

### `base.getLidarPointCloud()`

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

Get a point cloud from the named LiDAR sensor.

### `base.getOrientation()`

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

Get the chassis orientation in world frame.

Orientation is calculated from accumulated LiDAR-IMU odometry, with
the origin at the robot's initial orientation on startup.

**Returns:**

Orientation as a quaternion `(x, y, z, w)`.

**Raises:**

RuntimeError: If no odometry data has been received yet.

### `base.getPosition()`

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

Get the chassis position in world frame.

Position is calculated from accumulated LiDAR-IMU odometry, with
the origin at the robot's initial position on startup.

**Returns:**

Position in the world frame (meters).

**Raises:**

RuntimeError: If no odometry data has been received yet.

### `base.getState()`

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

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

### `base.moveByVelocity()`

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

Command chassis velocity.

The command is republished at 50 Hz until a new command (including
`stop`) is received, or until *duration* seconds have elapsed.

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

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

<ParamField body="frame" default="'body'">
  Reference frame for the velocity. Only `"body"` is supported; any other value (including `"world"`) raises.
</ParamField>

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

**Raises:**

ValueError: If *frame* is not `"body"`.

### `base.moveToPose()`

```python Signature theme={null}
base.moveToPose(
    pose: Pose,
    blocking: bool = True,
    *,
    frame: str = 'world',
    pos_threshold: float = 0.05,
    yaw_threshold: float = 0.05,
    max_linear_speed: float = 0.5,
    max_angular_speed: float = 1.0,
    kp_linear: float = 1.0,
    ki_linear: float = 0.1,
    kp_angular: float = 2.0,
    ki_angular: float = 0.2,
    integral_fraction: float = 0.2,
    timeout: float = 30.0,
) -> None
```

Drive the chassis to a target pose using a PI controller.

Commands body-frame velocities via `moveByVelocity` in a closed loop,
reading the current pose from the accumulated LiDAR-IMU odometry.
The controller runs at `_CMD_RATE_HZ` Hz and stops when the position
and yaw errors are both within their respective thresholds, or when
*timeout* is exceeded.

Only the yaw component of the pose's orientation is used — the chassis
cannot control roll or pitch.

!!! note
The world frame origin is the robot's position and heading at
startup.  When *frame* is `"world"`, coordinates are absolute
in that odometry frame.  When *frame* is `"body"`, the target
pose is interpreted as a delta relative to the current pose at
the time of the call.

!!! warning
Large yaw targets (more than roughly 10° from the current
heading) can exhibit hunting — limit-cycle oscillation around
the target yaw — under certain conditions, notably delayed or
stale odometry feedback. The move may then converge slowly or
hit *timeout*. A runtime warning is emitted when the initial
yaw error exceeds 10°. To mitigate, split the rotation into
smaller increments, lower `kp_angular`, or raise *timeout*.

<ParamField body="pose" required>
  Target pose. Only `position.x`, `position.y`, and the yaw component (rotation about Z) of `orientation` are used; `z`, roll, and pitch are ignored. Interpretation depends on *frame*: absolute world-frame coordinates when `"world"`, or a body-frame delta (dx forward, dy left, dyaw) when `"body"`.
</ParamField>

<ParamField body="blocking" default="True">
  This move always blocks until convergence or timeout; passing `blocking=False` logs a warning. Defaults to True.
</ParamField>

<ParamField body="frame" default="'world'">
  Reference frame for the target — `"world"` (default) for an absolute pose, or `"body"` for a delta relative to the current pose.
</ParamField>

<ParamField body="pos_threshold" default="0.05">
  Position convergence threshold in meters.
</ParamField>

<ParamField body="yaw_threshold" default="0.05">
  Yaw convergence threshold in radians.
</ParamField>

<ParamField body="max_linear_speed" default="0.5">
  Maximum linear velocity magnitude in m/s.
</ParamField>

<ParamField body="max_angular_speed" default="1.0">
  Maximum angular velocity magnitude in rad/s.
</ParamField>

<ParamField body="kp_linear" default="1.0">
  Proportional gain for XY position error.
</ParamField>

<ParamField body="ki_linear" default="0.1">
  Integral gain for XY position error.
</ParamField>

<ParamField body="kp_angular" default="2.0">
  Proportional gain for yaw error.
</ParamField>

<ParamField body="ki_angular" default="0.2">
  Integral gain for yaw error.
</ParamField>

<ParamField body="integral_fraction" default="0.2">
  Maximum fraction of max speed that the integral term can contribute (0.0 to 1.0). Limits windup so the integral handles steady-state error without causing overshoot on longer drives.
</ParamField>

<ParamField body="timeout" default="30.0">
  Maximum time in seconds before the controller gives up.
</ParamField>

**Raises:**

ValueError: If *frame* is not `"world"` or `"body"`.
RuntimeError: If no odometry data is available (localization node
not running), or if *timeout* is exceeded before convergence.

### `base.setBrakeMode()`

```python Signature theme={null}
base.setBrakeMode(engaged: bool) -> None
```

Engage or disengage the chassis brake.

<ParamField body="engaged" required>
  `True` to engage the brake, `False` to release.
</ParamField>

### `base.setJointAngles()`

```python Signature theme={null}
base.setJointAngles(
    angles: List[float],
    blocking: bool = False,
    moving_time: Optional[float] = None,
    accel_time: Optional[float] = None,
    *,
    velocities: List[float] = None,
) -> None
```

Set torso joint angles.

<ParamField body="angles" required>
  Target joint angles in radians. A scalar is broadcast to all 4 joints; a list or `np.ndarray` must have length 4.
</ParamField>

<ParamField body="blocking" default="False">
  Not honored. This method publishes the target and returns immediately; passing `blocking=True` logs a warning. Defaults to False.
</ParamField>

<ParamField body="moving_time">
  Unused -- accepted for interface compatibility.
</ParamField>

<ParamField body="accel_time">
  Unused -- accepted for interface compatibility.
</ParamField>

<ParamField body="velocities">
  Optional joint velocities in rad/s. A scalar is broadcast to all 4 joints. !!! note `blocking`, `moving_time`, and `accel_time` are accepted for compatibility with the base `Wheeled` interface but have no effect. The Galaxea motion controller handles trajectory timing internally.
</ParamField>

### `base.stop()`

```python Signature theme={null}
base.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: `left_arm.endFreeDrive`, `left_arm.followJointTrajectory`, `left_arm.startFreeDrive`, `right_arm.endFreeDrive`, `right_arm.followJointTrajectory`, `right_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 eleven on-board cameras the R1Pro 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

- [MobileManipulator](/python-api/robot-interface/mobilemanipulator.md)
- [IsaacMobileBimanual](/python-api/isaac-robots/isaacmobilebimanual.md)
- [Robot interface](/python-api/robot-interface/overview.md)
- [Robot](/python-api/robot-interface/robot.md)
- [Wheeled](/python-api/robot-interface/wheeled.md)
