Robots_ImportRobotModel
const url = 'https://junction-api.qualiastudios.dev/v1/accounts/example/robots/example/model:import';const options = { method: 'POST', headers: {'X-API-Key': '<X-API-Key>', 'Content-Type': 'application/json'}, body: '{"name":"example","object":"example"}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request POST \ --url https://junction-api.qualiastudios.dev/v1/accounts/example/robots/example/model:import \ --header 'Content-Type: application/json' \ --header 'X-API-Key: <X-API-Key>' \ --data '{ "name": "example", "object": "example" }'Imports the uploaded URDF with its meshes, replacing any model. Returns at once with import_state PENDING; fleet then, in the background, resolves package:// paths, converts meshes to GLB, guesses arms from link names (CONVERTING), swaps the model in (READY) and starts fitting capsules. A robot’s URDF with no link reached through three turning joints ends FAILED. A gripper design needs no arm, but at least one link, and ends FAILED when none of its visual meshes is in the upload (its fingers would draw as nothing). Poll GetRobotModel. FAILED_PRECONDITION while an import is PENDING or CONVERTING.
Authorizations
Section titled “Authorizations ”Parameters
Section titled “ Parameters ”Path Parameters
Section titled “Path Parameters ”The account id.
The robot id.
Request Body required
Section titled “Request Body required ”Request for Robots.ImportRobotModel.
object
Accounts/{account}/robots/{robot}/model
PrepareRobotModelImportResponse.object, after the file was PUT to its upload_uri. FAILED_PRECONDITION when nothing was uploaded there, or it belongs to another robot.
Example generated
{ "name": "example", "object": "example"}Responses
Section titled “ Responses ”OK
A robot’s kinematic model and the config every consumer shares: reach checks, retargeting, forward kinematics for trajectories, and the 3D gripper. One per robot.
Served by fleet.
object
Accounts/{account}/robots/{robot}/model
The URDF’s own robot name.
Signed URI of the browser-safe URDF: meshes point at the GLBs below.
The meshes.
One mesh, converted to GLB, at the path the served URDF references.
object
The path in the served URDF (package:// resolved to this relative path).
Signed URI of the GLB.
Content digest of the imported URDF and meshes.
Its arms: guessed at import (the deepest link named for each side, else one right arm), then edited.
One arm.
object
Which side.
The link the arm ends at.
The tool frame fixed in the hand link, where a handheld gripper root is held.
object
X, y, z in metres.
Roll, pitch, yaw in radians.
The posture a replay starts from: one angle per turning joint of the chain, radians, clamped to the limits.
The chain’s turning joints, base to hand, with their limits.
One turning joint, read off the URDF.
object
Joint name.
Lower limit, radians (or metres for prismatic).
Upper limit.
The arm’s TCP in the hand link’s frame, the one every reader of a robot’s
TCP uses (the reach solve at the TCP, the dashboard). A robot carrying a
gripper (Robot.carried_gripper): the hand link to the mount’s parent
link, then the mount, then the gripper’s own TCP; empty when the gripper
has no TCP for this side or it is stale, or the mount’s parent link is
not joined to the hand link by fixed joints. A robot carrying none: the
TCP its URDF names, the first link called grasp_frame, hand_tcp or
tcp (or ending _ and one of those) fixed below the hand link; empty
where it names none.
object
M[0..3] is the first row, m[12..15] the last.
Explicitly use this complete, in-limit start_posture as configured home for contact exclusions. Absent/false retains the replay rest seed without claiming imported, padded or clipped defaults are verified home.
The IK solver; SOLVER_UNSPECIFIED when none has been set (a new model has
none). Once set it can be changed to another, never cleared: naming
solver in the update mask with SOLVER_UNSPECIFIED, or with a value this
server does not know, is INVALID_ARGUMENT.
The gripper joint; unset when the robot has none.
object
Joint name; {side} is replaced by “left” or “right”.
Its position fully open.
Its position shut.
Explicit jaw position at the configured arm home, mirrored with the open/closed range where the side’s URDF limits require it. Absence means unknown, including on legacy profiles; never infer open, closed or zero.
Self-collision capsules.
Signed URI of the capsules JSON (pyroki’s export), when fitted.
Digest over digest, arms, solver, capsules, gripper and the solver’s parameters (mink_parameters for MINK, pyroki_parameters for PYROKI, the legacy numbers excepted). Reach results are keyed by it: after a change the stored results are for the old config, and nothing re-runs them until a reach check is asked for.
Who last changed it.
object
What kind of actor it is.
The person’s user id when kind is PERSON; empty otherwise.
The person’s display name at the time, for rendering without a lookup.
The rule code, or for a MODEL the Qualia model tier (e.g. “qualia-vlm”; “qualia” for any other model), when not a person.
The run a model or rule finding came from, when it has one.
The API key’s id when a person acted through one; empty for a session. Never the key itself.
Signed identity evidence recorded with the change, kept apart from the principal above. Unset on older records and wherever none was signed.
object
How the principal authenticated.
The user id of a person verified as starting the work: the person of a session, or the person a trusted service’s signed job record names. Empty when nobody was verified.
The initiator’s display name at the time, never their email.
The user id of the key’s creator at the time. Not who used the key.
Who owned the key at the time.
The owning space’s id (a workspace or the organization) when
credential_owner is SPACE.
When it last changed.
Sent back on UpdateRobotModel.
Where the latest import is. Until it is READY, the fields above describe the previous model (empty when there is none).
Why the latest import FAILED, e.g. “no link is reached through three turning joints”.
Where a dataset’s reach check starts when the dataset names no base of its own (ReachSettings.base_m): empty or exactly three numbers, metres in the robot’s base frame, each within 5 m either way. Not part of config_digest, so changing it makes no stored result stale; a dataset that follows it gets a new reach key on its next RunCheck. The reach op does not apply a base yet; see ReachSettings.base_m.
Digest of every arm’s TCP (Arm.tcp), empty when no arm has one. Reach results walked at the TCP are keyed by it beside config_digest, so a change to the carried gripper, its mount, its TCP or either URDF makes them stale; results walked at the gripper root do not depend on it.
What Mink solves with: set exactly when the solver is MINK, and then whole
(see MinkParameters). Set with UpdateRobotModel (update_mask
mink_parameters) together with solver MINK; any other solver clears
them. Part of config_digest, so changing them makes stored reach results
stale.
object
Each arm’s frame task on its tool frame: its position cost, 0 or more. pos_cost and ori_cost are not both 0.
The frame task’s orientation cost, 0 or more.
The frame task’s Levenberg-Marquardt damping, 0 or more.
The posture task’s cost on the arm joints, 0 or more.
What the posture task pulls the arm joints toward.
The smoothness task’s cost, 0 or more; 0 turns it off.
The elbow-down task’s cost, 0 or more; 0 turns it off.
The singularity task’s threshold, 0 or more; 0 turns it off.
The singularity task’s damping, 0 or more; 0 turns it off.
The QP’s step, above 0.
The QP’s Levenberg-Marquardt damping, 0 or more.
The most QP steps a row takes, 1 to 1000.
A row’s steps stop once every arm’s position error is within this and its orientation error within ori_tol; a 0 tolerance is never met.
The orientation tolerance that goes with pos_tol; 0 is never met.
A row’s steps stop once a step moves the joints less than this; 0 never stops one.
A row’s steps stop once its error shrank by less than min_progress over this many steps, 0 to 1000; 0 never stops one.
The share of its error a row must lose over progress_window steps to keep stepping, 0 or more and below 1.
Q-research’s checked step (inference) instead of mink.solve_ik (teleop).
The arm joints’ speed limit in the QP, 0 or more; 0 is no limit.
The arm joints’ speed limit from one row of the take to the next, 0 or more; 0 is no limit.
Whether the collision limit, on the robot’s capsules, is on.
The capsule pairs the collision limit watches.
The collision limit’s minimum distance, 0 or more.
The collision limit’s detection distance, above collision_min_distance.
The collision limit’s gain, above 0 and at most 1.
The collision limit’s bound relaxation, 0 or more.
The shoulder link’s name (“{side}” stands for left or right, at most 256 characters); empty is the arm chain’s 2nd joint’s child link.
The elbow link’s name, like shoulder_link; empty is the 4th joint’s child link.
The wrist link’s name, like shoulder_link; empty is the 5th joint’s child link.
What PyRoKi solves with: set exactly when the solver is PYROKI, and then
whole (see PyrokiParameters). Set with UpdateRobotModel (update_mask
pyroki_parameters) together with solver PYROKI, as mink_parameters is
with MINK; any other solver clears them. A PYROKI robot that has run before
holds the numbers it has always run. Part of config_digest, except that the
numbers every PyRoKi robot ran before it had a file add nothing, so a robot
that still holds them keeps the digest (and the stored reach results) it
had.
object
The pose cost’s weight on each hand’s position, 0 to 1e6. pos_weight and ori_weight are not both 0.
The pose cost’s weight on each hand’s orientation, 0 to 1e6.
The weight pulling each row toward the last answer, 0 to 1e6. It pulls toward the same value as anchor_weight, so only their sum of squares matters and tuning either has the same effect.
The weight pulling each row toward the row before it, 0 to 1e6. Not toward home: see last_weight.
The weight on the arm’s manipulability, 0 to 1e6.
The weight keeping the joints inside their limits, 0 to 1e6.
The weight keeping the arms’ capsules apart, 0 to 1e6.
How near two capsules may come before the collision cost acts, in metres, 0 to 1.
The most solver iterations a row takes, 1 to 50.
Example
{ "arms": [ { "side": "SIDE_UNSPECIFIED" } ], "solver": "SOLVER_UNSPECIFIED", "capsuleState": "CAPSULE_STATE_UNSPECIFIED", "editor": { "kind": "KIND_UNSPECIFIED", "attribution": { "authentication": "AUTHENTICATION_UNSPECIFIED", "credentialOwner": "CREDENTIAL_OWNER_UNSPECIFIED" } }, "importState": "IMPORT_STATE_UNSPECIFIED", "minkParameters": { "postureTarget": "POSTURE_TARGET_UNSPECIFIED", "collisionPairs": "COLLISION_PAIRS_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": [ {} ]}