Skip to content

Robots_UpdateRobot

PATCH
/v1/accounts/{account}/robots/{robot}
curl --request PATCH \
--url https://dev-api.qualiastudios.dev/v1/accounts/example/robots/example \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <X-API-Key>' \
--data '{ "name": "example", "displayName": "example", "robotType": "example", "serialNumber": "example", "etag": "example", "kind": "KIND_UNSPECIFIED", "owner": "example" }'

Edits display_name, robot_type or serial_number. Not the kind.

account
required
string

The account id.

robot
required
string

The robot id.

updateMask
string format: field-mask

Which fields to change: display_name, robot_type, serial_number.

Media type application/json

A robot the account keeps (fleet.robots). Episodes can be recorded on it (Dataset.source_robot) and played on it (Dataset.target_robot).

A gripper design (kind GRIPPER) is the same record: a URDF of one gripper with the TCP of each hand on it (gripper_tcp, QUA-3188), which is also what a handheld rig’s trackers are calibrated to and what Rig.gripper points at (ML-316). Everything that takes a robot name works on it (upload, model, delete), but it is no robot: ListRobots leaves it out unless asked for grippers, so it is never the default target, and Robot.config_digest is always empty (its RobotModel keeps one), so no reach result is keyed by it. It lives in one workspace. ListRobots with kind = GRIPPER makes the workspace’s “UMI handheld” gripper (rig_key “umi-handheld”) on first ask: an ordinary row, editable and deletable like any other.

A robot carries a gripper on its flanges (carried_gripper), set with SetRobotGripper, and owns it: attaching a gripper copies its URDF, TCP and jaw into a gripper design of the robot’s own (owner names the robot), so editing it changes that robot only. An owned gripper is carried by its owner alone, is included when listing grippers as a source to copy, is deleted with its robot, by detaching it, or by DeleteRobot on the gripper, and needs robots:write to change (a workspace-level gripper, such as the handheld’s, needs rigs:write). Everything that takes a gripper name works on it (GetRobot, the model, SetGripperTcp, ImportGripperCalibration).

Served by fleet.

object
name

Accounts/{account}/robots/{robot}

string
displayName
required

Unique per account.

string
robotType

The robot type key (fleet.robot_type.key), e.g. “openarm”, “franka_fr3”. Empty for a robot defined only by an imported URDF.

string
serialNumber

Serial number, free text.

string
hasModel

Whether the robot has a model (URDF) configured.

boolean
configDigest

RobotModel.config_digest, empty without a model: what reach results are keyed by. Always empty for a gripper design.

string
createTime

When it was registered.

string format: date-time
updateTime

When it last changed.

string format: date-time
etag

Sent back on UpdateRobot.

string
kind

Robot or gripper design. Set by CreateRobot (unset is ROBOT) and never changed.

string format: enum
Allowed values: KIND_UNSPECIFIED ROBOT GRIPPER
gripperTcp

Kind GRIPPER only: its TCPs.

object
hands

The hands that have a TCP: none, one or both sides.

Array<object>

One hand’s TCP.

object
side

Which hand.

string format: enum
Allowed values: SIDE_UNSPECIFIED SIDE_LEFT SIDE_RIGHT
link

The link of the gripper’s URDF that tcp is expressed in, with the side resolved (“openarm_left_ee_base_link”). Empty when the hand has only a tracker_to_tcp.

string
tcp

The TCP’s pose in link’s frame. Empty when the hand has none.

object
m

M[0..3] is the first row, m[12..15] the last.

Array<number>
trackerToTcp

The TCP’s pose in the tracker’s frame: what uploads are resolved with. Unset when the hand has none, so it serves robots only. (— api-linter: core::0140::prepositions=disabled aip.dev/not-precedent: a transform is named by its direction, as TcpCalibration.Hand.tracker_to_tcp is. —)

object
xyz

X, y, z in metres.

Array<number>
rpy

Roll, pitch, yaw in radians.

Array<number>
calibration

The hands’ tracker_to_tcp as a calibration, the form Datasets.ResolvePoses takes. Set only when resolves_uploads.

object
filename
required

The uploaded file’s name, e.g. “tcp_calibration.json”.

string
deriveDate

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.

string
hands
required

Both hands, left then right.

Array<object>

One hand’s transform.

object
side
required

Which hand.

string format: enum
Allowed values: SIDE_UNSPECIFIED SIDE_LEFT SIDE_RIGHT
trackerToTcp
required

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. (— api-linter: core::0140::prepositions=disabled aip.dev/not-precedent: a transform is named by its direction, as the calibration file’s own controller_to_tcp is. —)

object
xyz

X, y, z in metres.

Array<number>
rpy

Roll, pitch, yaw in radians.

Array<number>
eeToTcp

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. (— api-linter: core::0140::prepositions=disabled aip.dev/not-precedent: a transform is named by its direction, as the calibration file’s own ee_to_tcp is. —)

object
xyz

X, y, z in metres.

Array<number>
rpy

Roll, pitch, yaw in radians.

Array<number>
eeLink

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__ee_base_link at link7, 20.5 mm behind the frame the calibration is in.

string
rigKey

The ingest rig kind this gripper stands for, e.g. “umi-handheld”: what Dataset.poses_rig names. Unique among workspace-level grippers. Empty for a gripper that stands for none, and for the gripper a robot owns (see source_rig_key); a TCP on it serves robots only.

string
filename

The calibration file’s name, or “tcp-matrix:” for a matrix.

string
deriveDate

“YYYY-MM-DD”: the file’s, or the day the matrix was set (UTC). Empty when a file gave none.

string
stale

Whether the gripper’s URDF changed since a TCP in a link was set: a re-import changed its digest or took the link away. A stale TCP is shown with a warning and is never composed into a robot’s arm; set it again, every hand that has one in the same call.

boolean
tcpSet

Robots can use it: every hand has its TCP in a link and it is not stale.

boolean
resolvesUploads

Uploads can be resolved with it: both hands have a tracker_to_tcp, and the calibration has a file name and a date.

boolean
etag

Sent back on SetGripperTcp and ImportGripperCalibration.

string
sourceRigKey

The rig_key of the gripper this one was copied from, e.g. “umi-handheld”, for the gripper a robot owns; empty otherwise. It says the gripper is a copy of that rig’s gripper (and so has its controller to TCP transform), which a copy cannot claim as its own rig_key: uploads are resolved with the gripper that holds the key.

string
carriedGripper

Kind ROBOT only: the gripper it carries, if any.

object
gripper

Accounts/{account}/robots/{robot} of kind GRIPPER, in the robot’s workspace: the robot’s own gripper (its owner is the robot).

string
mounts

One per arm side the gripper is mounted on.

Array<object>

Where a gripper’s hand link sits on one arm.

object
side
required

Which arm.

string format: enum
Allowed values: SIDE_UNSPECIFIED SIDE_LEFT SIDE_RIGHT
parentLink

The robot’s link the gripper hangs off: it must be joined to the arm’s hand_link by fixed joints only.

string
matrix

The pose of the gripper’s hand link (its TCP link) in parent_link’s frame. Ignored when baked. The mount is for the link the hand’s TCP is in when it is set, which must exist then; a TCP set in another link later composes nothing until the mount is set again.

object
m

M[0..3] is the first row, m[12..15] the last.

Array<number>
baked

The robot’s own URDF already has the gripper built in, as the gripper design has it: the mount is the identity on the robot’s link of the gripper’s link name. The server checks that the two URDFs agree on where that link is (FAILED_PRECONDITION when they do not) and sets parent_link and matrix itself.

boolean
guessed

The mount was filled in by a guess and has not been confirmed.

boolean
etag

Sent back on SetRobotGripper.

string
displayName

The gripper’s display name (the one it was copied from), so a robot can say “gripper: KIWI gripper pair” without reading the gripper.

string
owner

Kind GRIPPER only: accounts/{account}/robots/{robot} of the robot that owns this gripper. Empty for a workspace-level gripper (the handheld’s, or a library gripper). Set on CreateRobot (with kind GRIPPER) to make the named robot’s own gripper, which that robot carries from then on (with no mounts); never changed after. (— api-linter: core::0121::no-mutable-cycles=disabled aip.dev/not-precedent: owner is set once, on CreateRobot, and never changed (it is IMMUTABLE), so the Robot to Robot reference cannot form a cycle: a gripper names the robot that owns it, and a robot never has an owner. —)

string
stagedGripperSupported

The server supports exact staged gripper copy and fenced replacement. Absent on older servers; clients must not assume those guarantees.

boolean
thumbnailSha256

The sha256 (lowercase hex) of the robot’s thumbnail, a picture of its model at the default pose that fleet draws when the model is imported (the bytes are GetRobotThumbnail’s). Empty when it has none yet, or when the model was replaced since it was drawn, so a replaced model never shows its old picture.

string

OK

Media type application/json

A robot the account keeps (fleet.robots). Episodes can be recorded on it (Dataset.source_robot) and played on it (Dataset.target_robot).

A gripper design (kind GRIPPER) is the same record: a URDF of one gripper with the TCP of each hand on it (gripper_tcp, QUA-3188), which is also what a handheld rig’s trackers are calibrated to and what Rig.gripper points at (ML-316). Everything that takes a robot name works on it (upload, model, delete), but it is no robot: ListRobots leaves it out unless asked for grippers, so it is never the default target, and Robot.config_digest is always empty (its RobotModel keeps one), so no reach result is keyed by it. It lives in one workspace. ListRobots with kind = GRIPPER makes the workspace’s “UMI handheld” gripper (rig_key “umi-handheld”) on first ask: an ordinary row, editable and deletable like any other.

A robot carries a gripper on its flanges (carried_gripper), set with SetRobotGripper, and owns it: attaching a gripper copies its URDF, TCP and jaw into a gripper design of the robot’s own (owner names the robot), so editing it changes that robot only. An owned gripper is carried by its owner alone, is included when listing grippers as a source to copy, is deleted with its robot, by detaching it, or by DeleteRobot on the gripper, and needs robots:write to change (a workspace-level gripper, such as the handheld’s, needs rigs:write). Everything that takes a gripper name works on it (GetRobot, the model, SetGripperTcp, ImportGripperCalibration).

Served by fleet.

object
name

Accounts/{account}/robots/{robot}

string
displayName
required

Unique per account.

string
robotType

The robot type key (fleet.robot_type.key), e.g. “openarm”, “franka_fr3”. Empty for a robot defined only by an imported URDF.

string
serialNumber

Serial number, free text.

string
hasModel

Whether the robot has a model (URDF) configured.

boolean
configDigest

RobotModel.config_digest, empty without a model: what reach results are keyed by. Always empty for a gripper design.

string
createTime

When it was registered.

string format: date-time
updateTime

When it last changed.

string format: date-time
etag

Sent back on UpdateRobot.

string
kind

Robot or gripper design. Set by CreateRobot (unset is ROBOT) and never changed.

string format: enum
Allowed values: KIND_UNSPECIFIED ROBOT GRIPPER
gripperTcp

Kind GRIPPER only: its TCPs.

object
hands

The hands that have a TCP: none, one or both sides.

Array<object>

One hand’s TCP.

object
side

Which hand.

string format: enum
Allowed values: SIDE_UNSPECIFIED SIDE_LEFT SIDE_RIGHT
link

The link of the gripper’s URDF that tcp is expressed in, with the side resolved (“openarm_left_ee_base_link”). Empty when the hand has only a tracker_to_tcp.

string
tcp

The TCP’s pose in link’s frame. Empty when the hand has none.

object
m

M[0..3] is the first row, m[12..15] the last.

Array<number>
trackerToTcp

The TCP’s pose in the tracker’s frame: what uploads are resolved with. Unset when the hand has none, so it serves robots only. (— api-linter: core::0140::prepositions=disabled aip.dev/not-precedent: a transform is named by its direction, as TcpCalibration.Hand.tracker_to_tcp is. —)

object
xyz

X, y, z in metres.

Array<number>
rpy

Roll, pitch, yaw in radians.

Array<number>
calibration

The hands’ tracker_to_tcp as a calibration, the form Datasets.ResolvePoses takes. Set only when resolves_uploads.

object
filename
required

The uploaded file’s name, e.g. “tcp_calibration.json”.

string
deriveDate

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.

string
hands
required

Both hands, left then right.

Array<object>

One hand’s transform.

object
side
required

Which hand.

string format: enum
Allowed values: SIDE_UNSPECIFIED SIDE_LEFT SIDE_RIGHT
trackerToTcp
required

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. (— api-linter: core::0140::prepositions=disabled aip.dev/not-precedent: a transform is named by its direction, as the calibration file’s own controller_to_tcp is. —)

object
xyz

X, y, z in metres.

Array<number>
rpy

Roll, pitch, yaw in radians.

Array<number>
eeToTcp

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. (— api-linter: core::0140::prepositions=disabled aip.dev/not-precedent: a transform is named by its direction, as the calibration file’s own ee_to_tcp is. —)

object
xyz

X, y, z in metres.

Array<number>
rpy

Roll, pitch, yaw in radians.

Array<number>
eeLink

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__ee_base_link at link7, 20.5 mm behind the frame the calibration is in.

string
rigKey

The ingest rig kind this gripper stands for, e.g. “umi-handheld”: what Dataset.poses_rig names. Unique among workspace-level grippers. Empty for a gripper that stands for none, and for the gripper a robot owns (see source_rig_key); a TCP on it serves robots only.

string
filename

The calibration file’s name, or “tcp-matrix:” for a matrix.

string
deriveDate

“YYYY-MM-DD”: the file’s, or the day the matrix was set (UTC). Empty when a file gave none.

string
stale

Whether the gripper’s URDF changed since a TCP in a link was set: a re-import changed its digest or took the link away. A stale TCP is shown with a warning and is never composed into a robot’s arm; set it again, every hand that has one in the same call.

boolean
tcpSet

Robots can use it: every hand has its TCP in a link and it is not stale.

boolean
resolvesUploads

Uploads can be resolved with it: both hands have a tracker_to_tcp, and the calibration has a file name and a date.

boolean
etag

Sent back on SetGripperTcp and ImportGripperCalibration.

string
sourceRigKey

The rig_key of the gripper this one was copied from, e.g. “umi-handheld”, for the gripper a robot owns; empty otherwise. It says the gripper is a copy of that rig’s gripper (and so has its controller to TCP transform), which a copy cannot claim as its own rig_key: uploads are resolved with the gripper that holds the key.

string
carriedGripper

Kind ROBOT only: the gripper it carries, if any.

object
gripper

Accounts/{account}/robots/{robot} of kind GRIPPER, in the robot’s workspace: the robot’s own gripper (its owner is the robot).

string
mounts

One per arm side the gripper is mounted on.

Array<object>

Where a gripper’s hand link sits on one arm.

object
side
required

Which arm.

string format: enum
Allowed values: SIDE_UNSPECIFIED SIDE_LEFT SIDE_RIGHT
parentLink

The robot’s link the gripper hangs off: it must be joined to the arm’s hand_link by fixed joints only.

string
matrix

The pose of the gripper’s hand link (its TCP link) in parent_link’s frame. Ignored when baked. The mount is for the link the hand’s TCP is in when it is set, which must exist then; a TCP set in another link later composes nothing until the mount is set again.

object
m

M[0..3] is the first row, m[12..15] the last.

Array<number>
baked

The robot’s own URDF already has the gripper built in, as the gripper design has it: the mount is the identity on the robot’s link of the gripper’s link name. The server checks that the two URDFs agree on where that link is (FAILED_PRECONDITION when they do not) and sets parent_link and matrix itself.

boolean
guessed

The mount was filled in by a guess and has not been confirmed.

boolean
etag

Sent back on SetRobotGripper.

string
displayName

The gripper’s display name (the one it was copied from), so a robot can say “gripper: KIWI gripper pair” without reading the gripper.

string
owner

Kind GRIPPER only: accounts/{account}/robots/{robot} of the robot that owns this gripper. Empty for a workspace-level gripper (the handheld’s, or a library gripper). Set on CreateRobot (with kind GRIPPER) to make the named robot’s own gripper, which that robot carries from then on (with no mounts); never changed after. (— api-linter: core::0121::no-mutable-cycles=disabled aip.dev/not-precedent: owner is set once, on CreateRobot, and never changed (it is IMMUTABLE), so the Robot to Robot reference cannot form a cycle: a gripper names the robot that owns it, and a robot never has an owner. —)

string
stagedGripperSupported

The server supports exact staged gripper copy and fenced replacement. Absent on older servers; clients must not assume those guarantees.

boolean
thumbnailSha256

The sha256 (lowercase hex) of the robot’s thumbnail, a picture of its model at the default pose that fleet draws when the model is imported (the bytes are GetRobotThumbnail’s). Empty when it has none yet, or when the model was replaced since it was drawn, so a replaced model never shows its old picture.

string
Example
{
"kind": "KIND_UNSPECIFIED",
"gripperTcp": {
"hands": [
{
"side": "SIDE_UNSPECIFIED"
}
],
"calibration": {
"hands": [
{
"side": "SIDE_UNSPECIFIED"
}
]
}
},
"carriedGripper": {
"mounts": [
{
"side": "SIDE_UNSPECIFIED"
}
]
}
}

Default error response

Media type application/json

The Status type defines a logical error model that is suitable for different programming environments, including REST APIs and RPC APIs. It is used by gRPC. Each Status message contains three pieces of data: error code, error message, and error details. You can find out more about this error model and how to work with it in the API Design Guide.

object
code

The status code, which should be an enum value of [google.rpc.Code][google.rpc.Code].

integer format: int32
message

A developer-facing error message, which should be in English. Any user-facing error message should be localized and sent in the [google.rpc.Status.details][google.rpc.Status.details] field, or localized by the client.

string
details

A list of messages that carry the error details. There is a common set of message types for APIs to use.

Array<object>

Contains an arbitrary serialized message along with a @type that describes the type of the serialized message.

object
@type

The type of the serialized message.

string
key
additional properties
any
Example generated
{
"code": 1,
"message": "example",
"details": [
{
"@type": "example"
}
]
}