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

# Robot arms

> Fixed-base manipulators: a single arm and a bimanual station with grippers and wrist force-torque sensors.

A fixed-base robot is `kind: "manipulator"`, with one `arm` part per arm. Its part poses are in the
**robot base frame**, and it has no body pose.

## A single arm

A Franka Panda with an external and a wrist camera is the end-to-end example in
[Writing a converter](/mcap-spec/examples/writing-a-converter). Its body is one part:

```json theme={null}
"platform": {
  "kind": "manipulator",
  "embodiment": "franka_panda",
  "parts": [{
    "name": "arm", "type": "arm",
    "joints":   {"signal": "arm_joints", "names": ["j1", "j2", "j3", "j4", "j5", "j6", "j7"]},
    "end_pose": {"channel": "/arm/ee_pose"},
    "grip":     {"signal": "gripper_opening"}
  }]
}
```

## A bimanual station

Two 6-DoF arms with parallel grippers and a force-torque sensor at each wrist, plus three cameras.

```json overlay.json theme={null}
{
  "spec_version": "1.1",
  "recording": {
    "id": "station-2-episode-004211",
    "clock": "log_time",
    "t0_ns": 1760000000000000000,
    "task": {
      "instruction": "Fold the shirt in half and place it in the bin.",
      "scene": "A flat shirt on the table, an empty bin to the right."
    },
    "platform": {
      "kind": "manipulator",
      "embodiment": "my_bimanual_station",
      "parts": [
        {"name": "left_arm", "type": "arm", "side": "left",
         "joints":   {"signal": "left_arm_joints", "names": ["j1", "j2", "j3", "j4", "j5", "j6"]},
         "end_pose": {"channel": "/left_arm/ee_pose"},
         "grip":     {"signal": "left_gripper"},
         "force":    {"signal": "left_wrist_wrench"}},
        {"name": "right_arm", "type": "arm", "side": "right",
         "joints":   {"signal": "right_arm_joints", "names": ["j1", "j2", "j3", "j4", "j5", "j6"]},
         "end_pose": {"channel": "/right_arm/ee_pose"},
         "grip":     {"signal": "right_gripper"},
         "force":    {"signal": "right_wrist_wrench"}}
      ]
    }
  },
  "primary_view": "/cam/top",
  "views": [
    {"channel": "/cam/top",         "role": "top",         "label": "Overhead"},
    {"channel": "/cam/left_wrist",  "role": "wrist_left",  "label": "Left wrist"},
    {"channel": "/cam/right_wrist", "role": "wrist_right", "label": "Right wrist"}
  ],
  "signals": [
    {"channel": "/sig/left_arm_joints", "name": "left_arm_joints", "type": "vector", "dim": 6,
     "components": ["j1", "j2", "j3", "j4", "j5", "j6"], "unit": "rad", "rate_hz": 50},
    {"channel": "/sig/right_arm_joints", "name": "right_arm_joints", "type": "vector", "dim": 6,
     "components": ["j1", "j2", "j3", "j4", "j5", "j6"], "unit": "rad", "rate_hz": 50},
    {"channel": "/sig/left_gripper", "name": "left_gripper", "type": "float", "unit": "1", "rate_hz": 50},
    {"channel": "/sig/right_gripper", "name": "right_gripper", "type": "float", "unit": "1", "rate_hz": 50},
    {"channel": "/sig/left_wrist_wrench", "name": "left_wrist_wrench", "type": "vector", "dim": 6,
     "components": ["fx", "fy", "fz", "tx", "ty", "tz"], "rate_hz": 500, "note": "N and N*m, sensor frame"},
    {"channel": "/sig/right_wrist_wrench", "name": "right_wrist_wrench", "type": "vector", "dim": 6,
     "components": ["fx", "fy", "fz", "tx", "ty", "tz"], "rate_hz": 500, "note": "N and N*m, sensor frame"},
    {"channel": "/sig/left_arm_joints_cmd", "name": "left_arm_joints_cmd", "type": "vector", "dim": 6,
     "components": ["j1", "j2", "j3", "j4", "j5", "j6"], "unit": "rad", "rate_hz": 50, "note": "commanded positions"},
    {"channel": "/sig/right_arm_joints_cmd", "name": "right_arm_joints_cmd", "type": "vector", "dim": 6,
     "components": ["j1", "j2", "j3", "j4", "j5", "j6"], "unit": "rad", "rate_hz": 50, "note": "commanded positions"}
  ]
}
```

## Notes

* **Gripper.** `grip` is the opening as a fraction: 0 = closed, 1 = fully open. Convert from your
  gripper's width (divide by its maximum width) or its command range in your converter.
* **End-effector pose.** `end_pose` is the tool-centre-point pose in the robot base frame. If you
  log only the end-effector position, publish it as a `PoseInFrame` with the identity orientation
  `(0, 0, 0, 1)` and say so in `source`.
* **Two bases.** When each arm has its own base, express both arms' poses in one shared frame
  (e.g. the left base, or the table), so the two tracks are comparable.
* **Commanded and measured.** `joints` is the **measured** state. Commanded positions, velocities
  and torques are ordinary signals, as `left_arm_joints_cmd` is here.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.