Robots_UpdateRobotModel
const url = 'https://dev-api.qualiastudios.dev/v1/accounts/example/robots/example/model';const options = { method: 'PATCH', headers: {'X-API-Key': '<X-API-Key>', 'Content-Type': 'application/json'}, body: '{"name":"example","arms":[{"side":"SIDE_UNSPECIFIED","handLink":"example","tool":{"xyz":[1],"rpy":[1]},"startPosture":[1],"startPostureConfigured":true}],"solver":"SOLVER_UNSPECIFIED","gripper":{"joint":"example","openPosition":1,"closedPosition":1,"homePosition":1},"etag":"example","reachBase":[1],"minkParameters":{"posCost":1,"oriCost":1,"frameLmDamping":1,"postureCost":1,"postureTarget":"POSTURE_TARGET_UNSPECIFIED","smoothnessCost":1,"elbowDownCost":1,"singularityThreshold":1,"singularityDamping":1,"dt":1,"damping":1,"maxIters":1,"posTol":1,"oriTol":1,"stallTol":1,"progressWindow":1,"minProgress":1,"checkedSteps":true,"maxJointVelocity":1,"maxJointSpeedPerRow":1,"selfCollision":true,"collisionPairs":"COLLISION_PAIRS_UNSPECIFIED","collisionMinDistance":1,"collisionDetectionDistance":1,"collisionGain":1,"collisionBoundRelaxation":1,"shoulderLink":"example","elbowLink":"example","wristLink":"example"}}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request PATCH \ --url https://dev-api.qualiastudios.dev/v1/accounts/example/robots/example/model \ --header 'Content-Type: application/json' \ --header 'X-API-Key: <X-API-Key>' \ --data '{ "name": "example", "arms": [ { "side": "SIDE_UNSPECIFIED", "handLink": "example", "tool": { "xyz": [ 1 ], "rpy": [ 1 ] }, "startPosture": [ 1 ], "startPostureConfigured": true } ], "solver": "SOLVER_UNSPECIFIED", "gripper": { "joint": "example", "openPosition": 1, "closedPosition": 1, "homePosition": 1 }, "etag": "example", "reachBase": [ 1 ], "minkParameters": { "posCost": 1, "oriCost": 1, "frameLmDamping": 1, "postureCost": 1, "postureTarget": "POSTURE_TARGET_UNSPECIFIED", "smoothnessCost": 1, "elbowDownCost": 1, "singularityThreshold": 1, "singularityDamping": 1, "dt": 1, "damping": 1, "maxIters": 1, "posTol": 1, "oriTol": 1, "stallTol": 1, "progressWindow": 1, "minProgress": 1, "checkedSteps": true, "maxJointVelocity": 1, "maxJointSpeedPerRow": 1, "selfCollision": true, "collisionPairs": "COLLISION_PAIRS_UNSPECIFIED", "collisionMinDistance": 1, "collisionDetectionDistance": 1, "collisionGain": 1, "collisionBoundRelaxation": 1, "shoulderLink": "example", "elbowLink": "example", "wristLink": "example" } }'Edits arms, solver, gripper, reach_base or mink_parameters.
Authorizations
Section titled “Authorizations ”Parameters
Section titled “ Parameters ”Path Parameters
Section titled “Path Parameters ”The account id.
The robot id.
Query Parameters
Section titled “Query Parameters ”Which fields to change: arms, solver, gripper, reach_base (naming it with none sent clears it), mink_parameters (a MINK model needs them whole; INVALID_ARGUMENT says which one a request gets wrong).
Request Body required
Section titled “Request Body required ”A robot’s kinematic model and the config every consumer shares: reach checks, retargeting, forward kinematics for trajectories, and the 3D gripper (QUA-2338, QUA-2339). 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.
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, for MINK, the Mink parameters. 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 the model id (e.g. “gemini-robotics-er”), 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.
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 (QUA-2338, QUA-2339). 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.
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, for MINK, the Mink parameters. 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 the model id (e.g. “gemini-robotics-er”), 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.
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
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
The status code, which should be an enum value of [google.rpc.Code][google.rpc.Code].
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.
A list of messages that carry the error details. There is a common set of message types for APIs to use.
Contains an arbitrary serialized message along with a @type that describes the type of the serialized message.
object
The type of the serialized message.
Example generated
{ "code": 1, "message": "example", "details": [ { "@type": "example" } ]}