{
  "openapi": "3.1.1",
  "info": {
    "title": "Kinetica Collision-Free Path Planner API",
    "version": "1.0.0",
    "summary": "Robot + start/goal + obstacles → collision-free joint path, timed within velocity/accel limits.",
    "description": "Every endpoint performs the same calculation as the human page and returns inputs, result, units, assumptions, sources, warnings and computedAt. MCP endpoint: /mcp."
  },
  "servers": [
    {
      "url": "https://kineticapathplanner.usefulweb.app"
    }
  ],
  "paths": {
    "/api/v1/calculate": {
      "post": {
        "operationId": "calculate",
        "summary": "Robot + start/goal + obstacles → collision-free joint path, timed within velocity/accel limits.",
        "description": "Plans a collision-free motion for a serial robot between two configurations (or to a TCP pose through IK) around box, sphere, capsule and cylinder obstacles and the robot itself. A seeded RRT-Connect search in joint space finds a path, shortcut smoothing removes detours, corners are rounded within a deviation bound, and a time-optimal parameterisation keeps every joint inside its velocity and acceleration limits. Returns the via points, the timed trajectory, CSV/JSON exports, clearance and singularity warnings — or says honestly that no path was found.\n\nMethodology:\n- Search: RRT-Connect (Kuffner & LaValle 2000) grows one tree from the start and one from the goal; every iteration draws a seeded pseudo-random configuration (mulberry32), extends one tree by at most 8% of the joint ranges towards it and greedily connects the other tree. Distances are measured with every joint scaled by its range. If the straight joint move is free, no search is run.\n- Collision checks: each configuration is tested with the same capsule/box distances as the collision-check tool (static base excluded, adjacent links and links touching at home ignored), after a bounding-sphere pre-test. Every edge is sampled at 1° per revolute and 2 mm per prismatic joint; motion between samples is not checked, so the safety margin should cover what can happen within one sample step.\n- Smoothing: seeded random shortcuts between two points on the path (kept only when the straight segment is free), then a greedy pass that connects each via point to the farthest directly reachable one.\n- Corners are rounded with circular blends in scaled joint space whose deviation from the checked polyline is at most the blend deviation (Kunz & Stilman 2012); each blend arc is collision-checked and halved up to six times, otherwise the robot stops at that via point.\n- Timing: on a grid of about 1000 points along the path (plus one per degree of turning in blends) the limits |q′ᵢ·ṡ| ≤ vᵢ and |q′ᵢ·s̈ + q″ᵢ·ṡ²| ≤ aᵢ are linear in (s̈, ṡ²) and are enforced at both ends of every grid interval; a backward pass computes the controllable velocities and a forward pass takes the largest admissible acceleration (TOPP-RA, Pham & Pham 2018). Samples are evaluated analytically; if discretisation lets one exceed a limit, the whole motion is slowed uniformly (reported as time scale), so every sample respects every limit. Rest-to-rest.\n- Verification: every output sample is re-checked with the reference collision checker for contact (clearance ≥ 0, reported as minimum clearance; a dip below the margin between checked configurations is reported as a warning), and manipulability (σmin/σmax) is scanned for near-singular stretches.\n\nKinematic simulation for planning and teaching, not robot control. The path is collision-free only against the simplified capsule/box envelope at the checked resolution; it is not a certified safety function. Verify every motion on the real controller with reduced speed and the cell safety system active.",
        "tags": [
          "apps"
        ],
        "x-mcp-tool": "kinetica_path_planner",
        "x-owner-app": "kinetica",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/KineticaPathPlannerInput"
              },
              "examples": {
                "example1": {
                  "summary": "6-axis arm swings around a wall in front of it",
                  "value": {
                    "robot": "kx6-1400",
                    "start": "-60, 30, 20, 0, 40, 0",
                    "goal": "j: 60, 30, 20, 0, 40, 0",
                    "obstacles": [
                      {
                        "name": "Wall",
                        "shape": "box",
                        "x": 800,
                        "y": 0,
                        "z": 600,
                        "sx": 400,
                        "sy": 200,
                        "sz": 1200
                      }
                    ],
                    "margin": 5
                  }
                },
                "example2": {
                  "summary": "Gantry over two walls (direct move would collide)",
                  "value": {
                    "robot": "gantry-xyz",
                    "start": "100, 400, -400",
                    "goal": "1100, 400, -400",
                    "obstacles": [
                      {
                        "name": "Wall A",
                        "shape": "box",
                        "x": 400,
                        "y": 400,
                        "z": 200,
                        "sx": 40,
                        "sy": 1000,
                        "sz": 400
                      },
                      {
                        "name": "Wall B",
                        "shape": "box",
                        "x": 800,
                        "y": 400,
                        "z": 200,
                        "sx": 40,
                        "sy": 1000,
                        "sz": 400
                      }
                    ],
                    "margin": 5
                  }
                },
                "example3": {
                  "summary": "Goal inside a closed fixture: no path (reported honestly)",
                  "value": {
                    "robot": "planar2",
                    "start": "0, 30",
                    "goal": "90, 0",
                    "obstacles": [
                      {
                        "name": "Side A",
                        "shape": "box",
                        "x": 80,
                        "y": 350,
                        "z": 50,
                        "sx": 40,
                        "sy": 500,
                        "sz": 100
                      },
                      {
                        "name": "Side B",
                        "shape": "box",
                        "x": -80,
                        "y": 350,
                        "z": 50,
                        "sx": 40,
                        "sy": 500,
                        "sz": 100
                      },
                      {
                        "name": "Lid",
                        "shape": "box",
                        "x": 0,
                        "y": 640,
                        "z": 50,
                        "sx": 240,
                        "sy": 40,
                        "sz": 100
                      }
                    ],
                    "margin": 0,
                    "maxIterations": 400
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/KineticaPathPlannerResult"
                }
              }
            }
          },
          "400": {
            "description": "Malformed JSON body.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "Invalid input (see errors[]).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (see Retry-After).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/tool": {
      "get": {
        "operationId": "getToolDefinition",
        "summary": "Inputs, output schema and examples for this tool",
        "responses": {
          "200": {
            "description": "Tool definition.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Problem": {
        "type": "object",
        "description": "RFC 9457 problem details. 422 responses include per-field `errors`.",
        "required": [
          "type",
          "title",
          "status",
          "detail"
        ],
        "properties": {
          "type": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "status": {
            "type": "integer"
          },
          "detail": {
            "type": "string"
          },
          "code": {
            "type": "string"
          },
          "errors": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "field",
                "message"
              ],
              "properties": {
                "field": {
                  "type": "string"
                },
                "message": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "KineticaPathPlannerInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "robot": {
            "title": "Robot",
            "description": "A library robot, or choose a custom DH table, URDF or Kinetica robot JSON.",
            "type": "string",
            "enum": [
              "kx6-1400",
              "ur5-like",
              "puma560",
              "scara-550",
              "gantry-xyz",
              "planar2",
              "custom-dh",
              "urdf",
              "json"
            ],
            "default": "kx6-1400"
          },
          "convention": {
            "title": "DH convention (custom table)",
            "type": "string",
            "enum": [
              "dh",
              "mdh"
            ],
            "default": "dh"
          },
          "dh": {
            "title": "DH table (custom)",
            "description": "One row per joint. Lengths in mm, angles in degrees. For revolute joints θ is the zero offset, for prismatic joints d is.",
            "type": "array",
            "maxItems": 12,
            "items": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "type": {
                  "title": "Type",
                  "type": "string",
                  "enum": [
                    "revolute",
                    "prismatic"
                  ],
                  "default": "revolute"
                },
                "a": {
                  "title": "a (mm)",
                  "type": "number",
                  "default": 0
                },
                "alpha": {
                  "title": "α (deg)",
                  "type": "number",
                  "default": 0
                },
                "d": {
                  "title": "d (mm)",
                  "type": "number",
                  "default": 0
                },
                "theta": {
                  "title": "θ (deg)",
                  "type": "number",
                  "default": 0
                },
                "min": {
                  "title": "min",
                  "type": "number"
                },
                "max": {
                  "title": "max",
                  "type": "number"
                },
                "vmax": {
                  "title": "v max (/s)",
                  "type": "number"
                },
                "amax": {
                  "title": "a max (/s²)",
                  "type": "number"
                }
              },
              "required": []
            }
          },
          "robotText": {
            "title": "URDF or robot JSON",
            "description": "Used when Robot is “URDF” or “Kinetica robot JSON”. URDF subset: links with box/cylinder/sphere, revolute/continuous/prismatic/fixed joints.",
            "type": "string",
            "maxLength": 400000
          },
          "tool": {
            "title": "Tool offset (TCP)",
            "description": "x, y, z (mm), roll, pitch, yaw (deg) in the flange frame, e.g. “0, 0, 150, 0, 0, 0”. Empty = robot default.",
            "type": "string",
            "default": ""
          },
          "projectJson": {
            "title": "Kinetica project JSON (optional)",
            "description": "A complete .kinetica.json project; its robot and obstacles are used instead of the robot fields (table obstacles are added). An empty start uses the project’s current pose.",
            "type": "string",
            "maxLength": 1000000
          },
          "start": {
            "title": "Start joints",
            "description": "Comma-separated joint values (deg / mm). Empty = home pose.",
            "type": "string",
            "default": ""
          },
          "goal": {
            "title": "Goal",
            "description": "Joint values (“j: 60, 30, 20, 0, 40, 0” or just the numbers) or a TCP pose “p: x, y, z, roll, pitch, yaw” (mm, deg) solved by IK.",
            "type": "string",
            "default": ""
          },
          "obstacles": {
            "title": "Obstacles",
            "description": "Box: centre x, y, z and size sx, sy, sz. Sphere: centre and r. Capsule or cylinder: start x, y, z, end x2, y2, z2 (in the size columns) and r. All in mm, world frame.",
            "type": "array",
            "maxItems": 50,
            "items": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "name": {
                  "title": "Name",
                  "type": "string",
                  "maxLength": 40
                },
                "shape": {
                  "title": "Shape",
                  "type": "string",
                  "enum": [
                    "box",
                    "sphere",
                    "capsule",
                    "cylinder"
                  ],
                  "default": "box"
                },
                "x": {
                  "title": "x",
                  "type": "number"
                },
                "y": {
                  "title": "y",
                  "type": "number"
                },
                "z": {
                  "title": "z",
                  "type": "number"
                },
                "sx": {
                  "title": "sx / x2",
                  "type": "number"
                },
                "sy": {
                  "title": "sy / y2",
                  "type": "number"
                },
                "sz": {
                  "title": "sz / z2",
                  "type": "number"
                },
                "r": {
                  "title": "r",
                  "type": "number",
                  "minimum": 0
                }
              },
              "required": [
                "x",
                "y",
                "z"
              ]
            }
          },
          "margin": {
            "title": "Safety margin",
            "type": "number",
            "minimum": 0,
            "maximum": 500,
            "default": 5,
            "x-unit": "mm"
          },
          "self": {
            "title": "Avoid self-collision",
            "type": "boolean",
            "default": true
          },
          "velocity": {
            "title": "Velocity limit",
            "description": "Share of every joint’s velocity limit.",
            "type": "number",
            "minimum": 1,
            "maximum": 100,
            "default": 100,
            "x-unit": "%"
          },
          "acceleration": {
            "title": "Acceleration limit",
            "description": "Share of every joint’s acceleration limit.",
            "type": "number",
            "minimum": 1,
            "maximum": 100,
            "default": 100,
            "x-unit": "%"
          },
          "deviation": {
            "title": "Corner blend deviation",
            "description": "Largest deviation of the rounded corners from the checked path, in % of the joint ranges. 0 = stop at every via point.",
            "type": "number",
            "minimum": 0,
            "maximum": 20,
            "default": 3,
            "x-unit": "%"
          },
          "seed": {
            "title": "Random seed",
            "type": "integer",
            "minimum": 0,
            "maximum": 2147483647,
            "default": 1
          },
          "maxIterations": {
            "title": "Max iterations",
            "type": "integer",
            "minimum": 10,
            "maximum": 20000,
            "default": 3000
          },
          "outputDt": {
            "title": "Output sample period",
            "type": "number",
            "minimum": 0.005,
            "maximum": 1,
            "default": 0.05,
            "x-unit": "s"
          }
        },
        "required": [
          "goal"
        ]
      },
      "KineticaPathPlannerResult": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "schemaVersion",
          "tool",
          "computedAt",
          "inputs",
          "summary",
          "result",
          "units",
          "assumptions",
          "sources",
          "warnings",
          "presentation",
          "links"
        ],
        "properties": {
          "schemaVersion": {
            "type": "string",
            "const": "1.0"
          },
          "tool": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "id",
              "name",
              "version"
            ],
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "version": {
                "type": "string"
              }
            }
          },
          "computedAt": {
            "type": "string",
            "format": "date-time"
          },
          "inputs": {
            "type": "object",
            "description": "Normalised inputs actually used, including applied defaults."
          },
          "summary": {
            "type": "string"
          },
          "result": {
            "type": "object",
            "required": [
              "ok",
              "reason",
              "message",
              "joints",
              "duration",
              "path",
              "stats",
              "verified",
              "samples"
            ],
            "properties": {
              "ok": {
                "type": "boolean"
              },
              "reason": {
                "type": "string",
                "enum": [
                  "direct",
                  "planned",
                  "start-outside-limits",
                  "goal-outside-limits",
                  "start-in-collision",
                  "goal-in-collision",
                  "no-path",
                  "goal-unreachable"
                ]
              },
              "message": {
                "type": "string"
              },
              "joints": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "start": {
                "type": "array",
                "items": {
                  "type": "number"
                }
              },
              "goal": {
                "type": [
                  "array",
                  "null"
                ],
                "items": {
                  "type": "number"
                }
              },
              "duration": {
                "type": "number"
              },
              "path": {
                "type": "array",
                "items": {
                  "type": "array",
                  "items": {
                    "type": "number"
                  }
                }
              },
              "stats": {
                "type": "object",
                "properties": {
                  "iterations": {
                    "type": "integer"
                  },
                  "treeNodes": {
                    "type": "array",
                    "items": {
                      "type": "integer"
                    }
                  },
                  "collisionChecks": {
                    "type": "integer"
                  },
                  "rawVertices": {
                    "type": "integer"
                  },
                  "vertices": {
                    "type": "integer"
                  },
                  "rawLength": {
                    "type": "number"
                  },
                  "length": {
                    "type": "number"
                  }
                }
              },
              "peaks": {
                "type": [
                  "object",
                  "null"
                ],
                "properties": {
                  "velocityPercent": {
                    "type": "array",
                    "items": {
                      "type": "number"
                    }
                  },
                  "accelerationPercent": {
                    "type": "array",
                    "items": {
                      "type": "number"
                    }
                  }
                }
              },
              "limits": {
                "type": [
                  "object",
                  "null"
                ],
                "properties": {
                  "velocity": {
                    "type": "array",
                    "items": {
                      "type": "number"
                    }
                  },
                  "acceleration": {
                    "type": "array",
                    "items": {
                      "type": "number"
                    }
                  }
                }
              },
              "timeScale": {
                "type": [
                  "number",
                  "null"
                ]
              },
              "stops": {
                "type": "integer"
              },
              "verified": {
                "type": "boolean"
              },
              "minClearance": {
                "type": [
                  "number",
                  "null"
                ]
              },
              "closest": {
                "type": [
                  "object",
                  "null"
                ]
              },
              "singularity": {
                "type": "object",
                "properties": {
                  "minInverseCondition": {
                    "type": "number"
                  },
                  "intervals": {
                    "type": "array",
                    "items": {
                      "type": "object"
                    }
                  }
                }
              },
              "samples": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "t": {
                      "type": "number"
                    },
                    "joints": {
                      "type": "array",
                      "items": {
                        "type": "number"
                      }
                    },
                    "velocity": {
                      "type": "array",
                      "items": {
                        "type": "number"
                      }
                    }
                  }
                }
              }
            }
          },
          "units": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "assumptions": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "sources": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "title"
              ],
              "properties": {
                "title": {
                  "type": "string"
                },
                "url": {
                  "type": "string"
                },
                "publisher": {
                  "type": "string"
                },
                "retrievedAt": {
                  "type": "string"
                },
                "note": {
                  "type": "string"
                }
              }
            }
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "presentation": {
            "type": "array",
            "items": {
              "type": "object"
            },
            "description": "Display blocks used by the human page (same data)."
          },
          "links": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "human",
              "api",
              "openapi",
              "methodology"
            ],
            "properties": {
              "human": {
                "type": "string",
                "format": "uri"
              },
              "api": {
                "type": "string",
                "format": "uri"
              },
              "openapi": {
                "type": "string",
                "format": "uri"
              },
              "methodology": {
                "type": "string",
                "format": "uri"
              }
            }
          }
        }
      }
    }
  }
}