# Robots_CreateSolverTemplate

`POST /v1/accounts/{account}/solverTemplates`

Registers a solver template from a solver file and returns it. A solver
template is a named solver choice with its parameters (a PyRoKi or Mink
solver file, or a bare DLS), kept in the workspace to apply to any number
of rigs: applying copies it into the rig (UpdateRobotModel with the
template's solver and parameters), so the rig keeps its own and editing or
deleting the template changes no rig. A template has no URDF; the Mink links
are checked against a rig's URDF when it is applied, not here. Needs
robots:write.

INVALID_ARGUMENT for a solver that is not PYROKI, DLS or MINK, parameters
that do not go with the solver (PyRoKi's and Mink's are checked whole, as
UpdateRobotModel checks them; DLS has none, so parameters beside it are
refused), a name that is empty or over 64 characters, or a name the
workspace's solver templates have (ALREADY_EXISTS). A retry with the same
`request_id` returns the first call's template.

- 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.
- `requestId` (query, string): Idempotency key (AIP-155): a retry with the same id within 24 hours returns
  the first call's template instead of making a second one.

## Request body

Required: `application/json` `qualia.v1.SolverTemplate`

## Responses

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

## Schemas

```yaml
qualia.v1.SolverTemplate:
  required:
    - displayName
    - solver
  type: object
  properties:
    name:
      type: string
      description: accounts/{account}/solverTemplates/{solver_template}
    displayName:
      type: string
      description: Unique per workspace, 1 to 64 characters.
    solver:
      enum:
        - SOLVER_UNSPECIFIED
        - PYROKI
        - DLS
        - MINK
      type: string
      description: |-
        PYROKI, DLS or MINK; SOLVER_UNSPECIFIED is INVALID_ARGUMENT. Never changed
        after creation.
      format: enum
    minkParameters:
      allOf:
        - $ref: "#/components/schemas/qualia.v1.RobotModel_MinkParameters"
      description: |-
        Set exactly when the solver is MINK, and then whole (see
        RobotModel.MinkParameters).
    pyrokiParameters:
      allOf:
        - $ref: "#/components/schemas/qualia.v1.RobotModel_PyrokiParameters"
      description: |-
        Set exactly when the solver is PYROKI, and then whole (see
        RobotModel.PyrokiParameters). DLS has no parameters.
    createTime:
      readOnly: true
      type: string
      description: When it was registered.
      format: date-time
    creator:
      readOnly: true
      allOf:
        - $ref: "#/components/schemas/qualia.v1.Actor"
      description: Who registered it, as events name an actor.
  description: |-
    A named solver choice with its parameters, kept in a workspace to apply to
    rigs (see CreateSolverTemplate). Served by fleet.
qualia.v1.RobotModel_MinkParameters:
  type: object
  properties:
    posCost:
      type: number
      description: |-
        Each arm's frame task on its tool frame: its position cost, 0 or more.
        pos_cost and ori_cost are not both 0.
      format: double
    oriCost:
      type: number
      description: The frame task's orientation cost, 0 or more.
      format: double
    frameLmDamping:
      type: number
      description: The frame task's Levenberg-Marquardt damping, 0 or more.
      format: double
    postureCost:
      type: number
      description: The posture task's cost on the arm joints, 0 or more.
      format: double
    postureTarget:
      enum:
        - POSTURE_TARGET_UNSPECIFIED
        - ENGAGE
        - ROW
      type: string
      description: What the posture task pulls the arm joints toward.
      format: enum
    smoothnessCost:
      type: number
      description: The smoothness task's cost, 0 or more; 0 turns it off.
      format: double
    elbowDownCost:
      type: number
      description: The elbow-down task's cost, 0 or more; 0 turns it off.
      format: double
    singularityThreshold:
      type: number
      description: The singularity task's threshold, 0 or more; 0 turns it off.
      format: double
    singularityDamping:
      type: number
      description: The singularity task's damping, 0 or more; 0 turns it off.
      format: double
    dt:
      type: number
      description: The QP's step, above 0.
      format: double
    damping:
      type: number
      description: The QP's Levenberg-Marquardt damping, 0 or more.
      format: double
    maxIters:
      type: integer
      description: The most QP steps a row takes, 1 to 1000.
      format: int32
    posTol:
      type: number
      description: |-
        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.
      format: double
    oriTol:
      type: number
      description: The orientation tolerance that goes with pos_tol; 0 is never met.
      format: double
    stallTol:
      type: number
      description: |-
        A row's steps stop once a step moves the joints less than this; 0
        never stops one.
      format: double
    progressWindow:
      type: integer
      description: |-
        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.
      format: int32
    minProgress:
      type: number
      description: |-
        The share of its error a row must lose over progress_window steps to
        keep stepping, 0 or more and below 1.
      format: double
    checkedSteps:
      type: boolean
      description: q-research's checked step (inference) instead of mink.solve_ik (teleop).
    maxJointVelocity:
      type: number
      description: The arm joints' speed limit in the QP, 0 or more; 0 is no limit.
      format: double
    maxJointSpeedPerRow:
      type: number
      description: |-
        The arm joints' speed limit from one row of the take to the next, 0 or
        more; 0 is no limit.
      format: double
    selfCollision:
      type: boolean
      description: Whether the collision limit, on the robot's capsules, is on.
    collisionPairs:
      enum:
        - COLLISION_PAIRS_UNSPECIFIED
        - ALL
        - AVOIDED
      type: string
      description: The capsule pairs the collision limit watches.
      format: enum
    collisionMinDistance:
      type: number
      description: The collision limit's minimum distance, 0 or more.
      format: double
    collisionDetectionDistance:
      type: number
      description: The collision limit's detection distance, above collision_min_distance.
      format: double
    collisionGain:
      type: number
      description: The collision limit's gain, above 0 and at most 1.
      format: double
    collisionBoundRelaxation:
      type: number
      description: The collision limit's bound relaxation, 0 or more.
      format: double
    shoulderLink:
      type: string
      description: |-
        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.
    elbowLink:
      type: string
      description: |-
        The elbow link's name, like shoulder_link; empty is the 4th joint's
        child link.
    wristLink:
      type: string
      description: |-
        The wrist link's name, like shoulder_link; empty is the 5th joint's
        child link.
  description: |-
    What Mink solves with (Solver MINK): schema 1 of the reach op's contract
    (op_reach.contract.MinkParameters). Every field is required: there are no
    defaults and no built-in sets. Metres, radians and seconds.
qualia.v1.RobotModel_PyrokiParameters:
  type: object
  properties:
    posWeight:
      type: number
      description: |-
        The pose cost's weight on each hand's position, 0 to 1e6. pos_weight and
        ori_weight are not both 0.
      format: double
    oriWeight:
      type: number
      description: The pose cost's weight on each hand's orientation, 0 to 1e6.
      format: double
    lastWeight:
      type: number
      description: |-
        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.
      format: double
    anchorWeight:
      type: number
      description: |-
        The weight pulling each row toward the row before it, 0 to 1e6. Not toward
        home: see last_weight.
      format: double
    manipulabilityWeight:
      type: number
      description: The weight on the arm's manipulability, 0 to 1e6.
      format: double
    limitWeight:
      type: number
      description: The weight keeping the joints inside their limits, 0 to 1e6.
      format: double
    collisionWeight:
      type: number
      description: The weight keeping the arms' capsules apart, 0 to 1e6.
      format: double
    collisionMargin:
      type: number
      description: |-
        How near two capsules may come before the collision cost acts, in metres,
        0 to 1.
      format: double
    maxIterations:
      type: integer
      description: The most solver iterations a row takes, 1 to 50.
      format: int32
  description: |-
    What PyRoKi solves with (Solver PYROKI): schema 1 of the PyRoKi solver
    file, as fleet checks it (q_fleet_api.services.pyroki_parameters). qds sends
    it to the reach op with each solve, as it sends a Mink robot's parameters. Every field is required: there are no defaults and no built-in
    sets. Weights are unitless, the margin is metres.
    Each robot has its own: PyRoKi on one robot and PyRoKi on another run the same
    solver and are tuned apart.
qualia.v1.Actor:
  type: object
  properties:
    kind:
      readOnly: true
      enum:
        - KIND_UNSPECIFIED
        - PERSON
        - VALIDATION
        - RULE
        - MODEL
        - OPERATOR
        - SYSTEM
      type: string
      description: What kind of actor it is.
      format: enum
    user:
      readOnly: true
      type: string
      description: The person's user id when `kind` is PERSON; empty otherwise.
    displayName:
      readOnly: true
      type: string
      description: The person's display name at the time, for rendering without a lookup.
    agent:
      readOnly: true
      type: string
      description: |-
        The rule code, or for a MODEL the Qualia model tier (e.g. "qualia-vlm";
        "qualia" for any other model), when not a person.
    run:
      readOnly: true
      type: string
      description: The run a model or rule finding came from, when it has one.
    apiKey:
      readOnly: true
      type: string
      description: |-
        The API key's id when a person acted through one; empty for a session.
        Never the key itself.
    attribution:
      readOnly: true
      allOf:
        - $ref: "#/components/schemas/qualia.v1.Attribution"
      description: |-
        Signed identity evidence recorded with the change, kept apart from the
        principal above. Unset on older records and wherever none was signed.
  description: Who did something. Every decision, issue and reply names one.
qualia.v1.Attribution:
  type: object
  properties:
    authentication:
      readOnly: true
      enum:
        - AUTHENTICATION_UNSPECIFIED
        - SESSION
        - API_KEY
        - SERVICE
      type: string
      description: How the principal authenticated.
      format: enum
    initiator:
      readOnly: true
      type: string
      description: |-
        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.
    initiatorDisplayName:
      readOnly: true
      type: string
      description: The initiator's display name at the time, never their email.
    credentialCreator:
      readOnly: true
      type: string
      description: The user id of the key's creator at the time. Not who used the key.
    credentialOwner:
      readOnly: true
      enum:
        - CREDENTIAL_OWNER_UNSPECIFIED
        - PERSON
        - SPACE
      type: string
      description: Who owned the key at the time.
      format: enum
    credentialOwnerSpace:
      readOnly: true
      type: string
      description: |-
        The owning space's id (a workspace or the organization) when
        `credential_owner` is SPACE.
  description: |-
    How a change was authenticated and who verifiably started it.
    Only the trusted mesh signs it. It never authorizes anything, and a key's
    creator or owner is never the person who used the key.
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.
```
