# Rigs_GetRig

`GET /v1/accounts/{account}/rigs/{rig}`

Gets one rig.

- Base URL: `https://junction-api.qualiastudios.dev`
- Authentication: an API key in the `X-API-Key` header

## Parameters

- `account` (path, string, required): The account id.
- `rig` (path, string, required): The rig id.

## Responses

- `200` OK: `application/json` `qualia.v1.Rig`
- `default` Default error response: `application/json` `google.rpc.Status`

## Schemas

```yaml
qualia.v1.Rig:
  required:
    - displayName
    - key
    - kind
  type: object
  properties:
    name:
      type: string
      description: accounts/{account}/rigs/{rig}
    displayName:
      type: string
      description: Human name.
    key:
      type: string
      description: |-
        What recordings carry as their rig id (meta/ingest.toml, LeRobot
        robot_type). Unique per account; 1 to 128 letters, digits, '.', '_', ':'
        or '-', starting with a letter or digit. Fixed at creation.
    kind:
      enum:
        - KIND_UNSPECIFIED
        - ARM
        - HANDHELD
      type: string
      description: Arm or handheld.
      format: enum
    robot:
      type: string
      description: |-
        Arm rig: accounts/{account}/robots/{robot} it drives, so its episodes get
        forward kinematics on that robot's model. A robot (not a gripper design)
        of the rig's own account; deleting the robot clears it. A handheld rig has
        none.
    mounts:
      type: array
      items:
        $ref: "#/components/schemas/qualia.v1.Rig_Mount"
      description: |-
        Handheld rig: one mount per tracked hand, at least one, at most one per
        side. An arm rig has none.
    createTime:
      readOnly: true
      type: string
      description: When it was created.
      format: date-time
    updateTime:
      readOnly: true
      type: string
      description: When it last changed.
      format: date-time
    etag:
      type: string
      description: Sent back on UpdateRig.
    calibration:
      readOnly: true
      allOf:
        - $ref: "#/components/schemas/qualia.v1.TcpCalibration"
      description: |-
        Handheld rig: where each tracker's TCP is, from the last
        ImportCalibration. Unset until one is imported, and never set on the
        built-in rig. Not editable through UpdateRig.
    builtin:
      readOnly: true
      type: boolean
      description: |-
        Whether this is a built-in rig (the UMI handheld rig): read only, the same
        in every account. Setting a gripper on one makes the account's own copy.
    gripper:
      type: string
      description: |-
        Handheld rig: accounts/{account}/robots/{robot} of kind GRIPPER, the
        design of its gripper (a URDF, imported as a robot model). A design of the
        rig's own account; deleting the design clears it. A design lives in one
        workspace, like any robot, and a rig in none, so this may name a design of
        any workspace of the account, and Robots.GetRobot finds it only from that
        workspace. Set with UpdateRig (CreateRig refuses it); on the built-in rig
        that makes the account's own copy, uncalibrated. An arm rig has none; it
        names a robot.
  description: |-
    A capture rig: what episodes are recorded with. An arm rig drives a fleet
    robot; a handheld (UMI) rig carries trackers whose fixed mount to each
    gripper root belongs here, not to any robot. Episodes name their
    rig by `key` (Episode.rig).

    The UMI handheld rig (key `umi-handheld`) is built in: every account lists
    and reads it under its own name, and nobody edits or deletes it
    (FAILED_PRECONDITION). An account rig with the same key takes its place, so
    an account records its own calibration of its UMI pair by creating one, or
    by setting a gripper on the built-in (UpdateRig), which makes that copy
    itself. An account may delete its copy; it then lists the built-in again,
    uncalibrated.

    A handheld rig may carry the TCP calibration of its trackers (`calibration`)
    and the design of its gripper (`gripper`, a Robot of kind GRIPPER): the
    gripper's URDF, with the calibration saying where on it the TCP is. Both are
    a record on the rig: importing or replacing either changes no dataset.
    Ingest reads only the calibration's `tracker_to_tcp`, `filename` and
    `derive_date`; the gripper design and the calibration's end-effector fields
    (`ee_link`, `ee_to_tcp`) are for display.

    Served by fleet.
qualia.v1.Rig_Mount:
  required:
    - side
    - trackerPose
  type: object
  properties:
    side:
      enum:
        - SIDE_UNSPECIFIED
        - SIDE_LEFT
        - SIDE_RIGHT
      type: string
      description: Which hand.
      format: enum
    trackerPose:
      allOf:
        - $ref: "#/components/schemas/qualia.v1.Transform"
      description: |-
        The fixed mount: the tracker's pose in its gripper root's frame (x along
        the fingers, y the way the jaw opens, z along the hinge): xyz in metres
        and rpy in radians like every Transform. meta/ingest.toml's
        [rig.mount.<side>] gives the same pose with rpy in degrees. Unset xyz or
        rpy read as zeros.
    openAngle:
      type: number
      description: "The gripper's closure calibration: the raw angle fully open."
      format: double
    closedAngle:
      type: number
      description: The raw angle shut.
      format: double
  description: One tracker's fixed mount.
qualia.v1.Transform:
  type: object
  properties:
    xyz:
      type: array
      items:
        type: number
        format: double
      description: x, y, z in metres.
    rpy:
      type: array
      items:
        type: number
        format: double
      description: roll, pitch, yaw in radians.
  description: |-
    A 3D rigid transform: translation in metres and roll, pitch, yaw in radians
    (URDF convention, extrinsic XYZ).
qualia.v1.TcpCalibration:
  required:
    - filename
    - hands
  type: object
  properties:
    filename:
      type: string
      description: The uploaded file's name, e.g. "tcp_calibration.json".
    deriveDate:
      type: string
      description: |-
        When the calibration was made, "YYYY-MM-DD": the leading date of the
        file's `calibrated` or else its `derived` text. Empty when the file gives
        none.
    hands:
      type: array
      items:
        $ref: "#/components/schemas/qualia.v1.TcpCalibration_Hand"
      description: Both hands, left then right.
    eeLink:
      type: string
      description: |-
        The link of the rig's gripper design that `Hand.ee_to_tcp` is a pose in,
        with `{side}` for "left" or "right" (the gripper joint's convention in
        RobotModel.Gripper), e.g. "openarm_{side}_ee_base_link". Read from the
        file's own description of its end-effector frame. Empty when the file
        names none, lacks the end-effector poses, or they disagree with its
        controller_to_tcp (then no `ee_to_tcp` is set either). Display only.

        `ee_to_tcp` is drawn in this link's own frame, which must be the plain
        end-effector frame the file means. An export whose link sits elsewhere
        draws the TCP off by the difference: an OpenArm exported with the xacro
        default collapse_internal_empty_links puts openarm_<side>_ee_base_link at
        link7, 20.5 mm behind the frame the calibration is in.
  description: |-
    A handheld rig's calibration of its trackers to the gripper's tool centre
    point (TCP, the midpoint of the closed fingertips). It is what a tcp_calibration.json holds as `<side>.controller_to_tcp`: the TCP's pose in
    the tracker's frame, so a pose recorded at a tracker becomes the pose of the
    TCP by composing it with this transform.

    A file that also names the gripper's end-effector link gives the same TCP in
    that link's frame (`ee_link`, `Hand.ee_to_tcp`), which is what a rig's
    gripper design (Rig.gripper) draws the TCP with. Those two are for display:
    poses are resolved and uploads converted with `tracker_to_tcp`, `filename`
    and `derive_date` alone, never with `ee_to_tcp`. So compare two calibrations
    on those, `hands[].side` and `hands[].tracker_to_tcp` only: a copy kept
    elsewhere (a dataset keeps the calibration its poses were resolved with)
    carries just those, and a whole-message comparison would call every
    calibration that has the end-effector fields replaced.
qualia.v1.TcpCalibration_Hand:
  required:
    - side
    - trackerToTcp
  type: object
  properties:
    side:
      enum:
        - SIDE_UNSPECIFIED
        - SIDE_LEFT
        - SIDE_RIGHT
      type: string
      description: Which hand.
      format: enum
    trackerToTcp:
      allOf:
        - $ref: "#/components/schemas/qualia.v1.Transform"
      description: |-
        The TCP's pose in the tracker's frame: xyz in metres and rpy in radians
        (URDF convention, extrinsic XYZ), the file's rotation matrix converted.
        A rotation whose pitch is within a hair of +-90 degrees has no unique
        roll and yaw; it is stored with roll 0.
    eeToTcp:
      allOf:
        - $ref: "#/components/schemas/qualia.v1.Transform"
      description: |-
        The same TCP in the frame of the gripper design's `ee_link` for this
        hand, in the form of `tracker_to_tcp` (so the same pitch limit). Display
        only. Set with `ee_link` or not at all, and only when it composes with
        the file's controller_to_ee to the file's controller_to_tcp, which is
        what makes the TCP drawn the TCP used.
  description: One hand's transform.
google.rpc.Status:
  oneOf:
    - $ref: "#/components/schemas/ApiError"
    - $ref: "#/components/schemas/GatewayError"
  description: "The body of a failed call: one of the two shapes below."
ApiError:
  title: API error
  type: object
  required:
    - code
    - message
    - retryable
    - details
  properties:
    code:
      type: string
      description: The gRPC code name in upper case, e.g. `NOT_FOUND`.
    message:
      type: string
    retryable:
      type: boolean
      description: Whether the same call may succeed if retried.
    details:
      type: array
      items:
        type: object
      description: "Empty, except when a dataset copy or move is refused: then one `google.rpc.ErrorInfo` with the refusal's `reason` code, its `domain` and, in `metadata`, the datasets it names."
  description: A refusal from the API itself.
GatewayError:
  title: Gateway error
  type: object
  required:
    - detail
  properties:
    detail:
      type: string
      description: What went wrong.
  description: A refusal from the gateway before the call reaches the API, for example `401` bad or missing API key, `403` key lacks the scope or environment closed, `413` body too large.
```
