Robots_ListRobots
const url = 'https://junction-api.qualiastudios.dev/v1/accounts/example/robots';const options = {method: 'GET', headers: {'X-API-Key': '<X-API-Key>'}};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request GET \ --url https://junction-api.qualiastudios.dev/v1/accounts/example/robots \ --header 'X-API-Key: <X-API-Key>'Lists the account’s robots, oldest first (the first is the default
target). Gripper designs and robot templates are left out: the filter
kind = GRIPPER lists the grippers instead (the workspace-level ones, gripper
templates and UMI rigs, which gripper_tcp.rig_kind tells apart, and the
copies robots own, each named like its source; its owner is the robot that
carries it), and kind = ROBOT_TEMPLATE the robot templates. Listing
grippers makes nothing: a workspace with no UMI rig lists none.
Authorizations
Section titled “Authorizations ”Parameters
Section titled “ Parameters ”Path Parameters
Section titled “Path Parameters ”The account id.
Query Parameters
Section titled “Query Parameters ”At most this many; 0 means 100, the maximum is 500.
From a previous response’s next_page_token, taken with the same filter.
AIP-160 filter, one term on kind, by the Robot.Kind value name:
kind = ROBOT or kind = GRIPPER (the name may be quoted). Empty lists
robots only. Anything else is INVALID_ARGUMENT.
Responses
Section titled “ Responses ”OK
Response for Robots.ListRobots.
object
One page of robots.
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), which is also what
a handheld rig’s trackers are calibrated to and what Rig.gripper points at. 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. A workspace-level gripper is one of two things: a
gripper template (gripper_tcp.rig_kind empty), the design a robot’s gripper
or a UMI rig is copied from, or a UMI rig (gripper_tcp.rig_kind
“umi-handheld”), the capture rig a handheld recording is converted
with: made by CopyGripperAsUmiRig from a gripper template and calibrated with
ImportGripperCalibration. A workspace has as many UMI rigs as someone made
and none otherwise: nothing makes one on listing, and a UMI rig is deleted
like any other robot.
A robot template (kind ROBOT_TEMPLATE) is the model of a robot
that rigs are made from: a URDF with its meshes and arms, and nothing a rig
adds (no solver, gripper, serial number, credentials, datasets or reach
results). CopyRobot makes a rig from it. The copy is a snapshot and shares
nothing with the template afterwards, and deleting the template never
touches a rig.
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, a gripper template or
a UMI rig, needs rigs:write). Everything that takes a gripper name works on
it (GetRobot, the model, SetGripperTcp, ImportGripperCalibration).
Served by fleet.
object
Accounts/{account}/robots/{robot}
Unique per account.
The robot type key (fleet.robot_type.key), e.g. “openarm”, “franka_fr3”. Empty for a robot defined only by an imported URDF.
Serial number, free text.
Whether the robot has a model (URDF) configured.
RobotModel.config_digest, empty without a model: what reach results are keyed by. Always empty for a gripper design.
When it was registered.
When it last changed.
Sent back on UpdateRobot.
Robot, robot template or gripper design. Set by CreateRobot (unset is ROBOT) and never changed.
Kind GRIPPER only: its TCPs.
object
The hands that have a TCP: none, one or both sides.
One hand’s TCP.
object
Which hand.
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.
The TCP’s pose in link’s frame. Empty when the hand has none.
object
M[0..3] is the first row, m[12..15] the last.
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.
object
X, y, z in metres.
Roll, pitch, yaw in radians.
The hands’ tracker_to_tcp as a calibration, the form
Datasets.ResolvePoses takes. Set only when resolves_uploads.
object
The uploaded file’s name, e.g. “tcp_calibration.json”.
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.
Both hands, left then right.
One hand’s transform.
object
Which hand.
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.
object
X, y, z in metres.
Roll, pitch, yaw in radians.
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.
object
X, y, z in metres.
Roll, pitch, yaw in radians.
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_
The key a recording may name this gripper by, e.g. “umi-handheld” on a
workspace’s first UMI rig, which also stands for the ingest rig kind of the
same name (rig_kind). Unique among workspace-level grippers. Empty for a
gripper that has none: a gripper template, a UMI rig made by CopyGripperAsUmiRig
(named by its name or id), and the gripper a robot owns (see
source_rig_key); a TCP on it serves robots only. Nothing makes a keyed
gripper any more: the key stays on the ones that have it.
The calibration file’s name, or “tcp-matrix:
“YYYY-MM-DD”: the file’s, or the day the matrix was set (UTC). Empty when a file gave none.
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.
Robots can use it: every hand has its TCP in a link and it is not stale.
Uploads can be resolved with it: both hands have a tracker_to_tcp, and
the calibration has a file name and a date.
Sent back on SetGripperTcp and ImportGripperCalibration.
The rig_kind (else 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 a UMI rig’s gripper (and so has its controller to
TCP transform), which a copy cannot claim as its own rig_kind: uploads are
resolved with a UMI rig.
The ingest rig kind this gripper converts a recording with, e.g.
“umi-handheld”: what Dataset.poses_rig names. Set exactly on a UMI rig (a
workspace-level gripper made by CopyGripperAsUmiRig, or the one a workspace had
before: its rig_key is the same string). Several UMI rigs of one kind may exist in
a workspace. Empty on a gripper template and on a gripper a robot owns.
Kind ROBOT only: the gripper it carries, if any.
object
Accounts/{account}/robots/{robot} of kind GRIPPER, in the robot’s
workspace: the robot’s own gripper (its owner is the robot).
One per arm side the gripper is mounted on.
Where a gripper’s hand link sits on one arm.
object
Which arm.
The robot’s link the gripper hangs off: it must be joined to the arm’s
hand_link by fixed joints only.
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[0..3] is the first row, m[12..15] the last.
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.
The mount was filled in by a guess and has not been confirmed.
Sent back on SetRobotGripper.
The gripper’s display name (the one it was copied from), so a robot can say “gripper: KIWI gripper pair” without reading the gripper.
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.
The server supports exact staged gripper copy and fenced replacement. Absent on older servers; clients must not assume those guarantees.
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.
RobotModel.solver, so a reader of the robot knows whether it has one
without reading the model (whose signed URLs cost fleet more than the
answer is worth). SOLVER_UNSPECIFIED: the robot has no solver, or no model;
has_model tells which. Always SOLVER_UNSPECIFIED for a gripper design.
fleet always sets it, SOLVER_UNSPECIFIED included, so a reader that finds
it unset is talking to an older fleet, which does not know the field, and
reads the model’s solver instead.
Accounts/{account}/robots/{robot} of the template this record was copied from: for a robot, the robot template CopyRobot copied (or the template of the robot it copied); for a gripper, the gripper template it was copied from (a UMI rig made by CopyGripperAsUmiRig, or the copy a robot owns). Empty when it was made another way, copied from something that was no template, or its template was deleted. It is provenance only: nothing is re-synced from it.
Empty on the last page.
Example
{ "robots": [ { "kind": "KIND_UNSPECIFIED", "gripperTcp": { "hands": [ { "side": "SIDE_UNSPECIFIED" } ], "calibration": { "hands": [ { "side": "SIDE_UNSPECIFIED" } ] } }, "carriedGripper": { "mounts": [ { "side": "SIDE_UNSPECIFIED" } ] }, "solver": "SOLVER_UNSPECIFIED" } ]}default
Section titled “default ”Default error response
A refusal from the API itself.
object
The gRPC code name in upper case, e.g. NOT_FOUND.
Whether the same call may succeed if retried.
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.
object
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.
object
What went wrong.
Example generated
{ "code": "example", "message": "example", "retryable": true, "details": [ {} ]}