Toolpaths

The toolpath endpoints are divided in two categories: the ones that affect a saved toolpath and the ones that work on an unsaved toolpath given as argument. The latter will be presented in the Unsaved actions category.

Note that every user has their own toolpaths, they are not shared between users by default (see Sharing to learn more about that).

Terms

Toolpath

A toolpath is the JSON representation of what you are seeing when programming the Robot in the Interface. It contains 3 properties: metadata, timeline and waypoints.

metadata is an object containing information about the toolpath. It supports multiple properties:

  • version: which is an integer indicating the version of the toolpath format, the current latest version is 2. The API will not accept a toolpath using an older version but you can call the migration endpoint to transform it beforehand. A list of changes between versions is also provided here
  • default_max_speed: which is a float representing the maximum speed (in m/s) that the robot end-effector will reach on trajectories with no explicit time or max_speed arguments
  • analog_modes: which is an object containing multiple properties (see I/O section for more information):

    • i0: mode of the first analog input (base), a string that can be either voltage (V) or current (mA)
    • i1: mode of the second analog input (base), same as previous
    • o0: mode of the first analog output (base), same as previous
    • o1: mode of the second analog output (base), same as previous
  • next_label_id: an integer indicating the next label_id a waypoint can use (see waypoints specification below), usually just the last used one + 1 (but can skip a few numbers)

  • payload: a float indicating the payload of the robot in kilogrammes
  • output_on_error: (optional) an object similar to one of type output-set (see next paragraph about timeline) which will be executed if an error while the robot is running this toolpath
  • tcp_config: (optional) an object representing the tool attached to the robot end-effector (see TCP configuration)
  • avoidance_zones: (optional) an array representing the different avoidance zones that the robot will use for this toolpath (see Software Avoidance Zones)

timeline is an array representing a list of actions to execute to complete the toolpath. Each action has different properties, here is the list sorted by type:

  • home: define where the Robot must be at the start of the toolpath, must be place before any trajectory and only once, in the root timeline (not in a grid, if, etc)

    • waypoint_id: an integer corresponding to the index in the waypoints array that represent the home
  • trajectory: this can either represent a move to a waypoint or a passthrough waypoint used in other trajectories

    • waypoint_id: an integer corresponding to the index in the waypoints array that the Robot should move to/passthrough
    • pass_through: (optional) a boolean that represent if the waypoint is a passthrough
    • trajectory: used to denote a move to this waypoint (no passthrough), can be either joint_space (fastest motion but may not maintain tool orientation), linear (will move in a straight line and maintain tool orientation) or spline (will make an arc and maintain tool orientation), note that the trajectory will go through the all previous passthrough waypoints since the last non-passthrough one (where possible, only spline at the moment)
    • time/max_speed: used when moving to a waypoint (no passthrough), these properties are used to describe how fast the robot will go to the waypoint, you can choose either:
      • time: a float representing the number of seconds the robot should take to go to the next waypoint
      • max_speed: a float representing the maximum speed the robot end-effector will reach when going to the next waypoint
      • none: if neither of these attributes are given, it will default to max_speed mode using the toolpath default_max_speed
  • output-set:

    • io: an object representing the IO to set (see I/O definition)
    • value: a boolean (for digital) or a float (for analog) describing the value to be set to the output described by io (see I/O for more information)
  • wait: will make the Robot wait at its current position until the condition is valid

    • condition: the condition to be tested, see the condition list next
  • restart: will stop the toolpath and restart from the start, need the last trajectory before this action to be the same as the one at the beginning of the toolpath, can only be placed at the end of if action branch

  • grid: allows you to define a 2D table (with rows and columns) over which the Robot will iterate with a special waypoint representing the current cell

    • cols: an integer for the number of columns of the table
    • rows: an integer for the number of rows of the table
    • w0: an integer corresponding to the index in the waypoints array of the waypoint defining the first corner of the table (note that w0-wx and w0-wy must be perpendicular segments)
    • wx: an integer corresponding to the index in the waypoints array of the waypoint defining the column (X) corner of the table
    • wy: an integer corresponding to the index in the waypoints array of the waypoint defining the row (Y) corner of the table
    • timeline: the timeline to be executed for every cell of the table, can contain the same actions as the root timeline (including grid actions). This timeline can also hold a special waypoint of the type grid-waypoint.
  • grid-waypoint: variable waypoint that changes position depending on the iteration of its parent grid

    • time/max_speed: same as for waypoint types
    • z_offset: a float that represent the offset from the grid plane (less is under, more is above), expressed in meters
  • if: allows you to fork your timeline in different branches, each branch has a condition, the first valid one of the list will determined the branch taken by the Robot, if no condition are valid, the entire action will be ignored

    • branches: the list of possible branches

      • condition: the condition to be tested, see the condition list next
      • timeline: the timeline to be executed, can contain the same actions as the root timeline (including if actions)
  • call-routine: will call a routine from the routines list (see lower down), executing it fully before moving to the next element in the timeline

    • name: a string matching the name of a routine from the routines array

Conditions can be either:

  • time (only for wait): condition is invalid until a certain duration is reached

    • duration: a float for the duration to wait for, in second
  • input or output-test: these conditions both test that an input or output (respectively) has a certain value

    • io: an object representing the IO to check (see I/O definition)
    • operator: in case of an analog I/O, this string describes how to test if the value is valid, can be either equal (must be the exact value), below (value < thresholds.lower), above (value > thresholds.upper), inside (thresholds.lower < value < thresholds.upper) or outside (value < thresholds.lower && thresholds.upper < value)
    • thresholds: in case of an analog I/O with operator other than equal, an object containing 2 properties: upper and lower describing the thresholds used by the operator property
    • value: a boolean (for digital) or a float (for analog with a equal operator) describing the value we are expecting for io

waypoints is an array of waypoint that can be used by the timeline actions of type trajectory (their waypoint_id being their index in this array). A waypoint can be used any number of times in any order. Each waypoint contains 2 properties:

  • label_id: a number used to identify a waypoint in space and in the timeline, the ordering can be any way you want but a number cannot be repeated (though some can be skipped)
  • label: (optional) a string to help identify a waypoint (maximum 16 characters)
  • joints: an array of 6 floats the joint angles of the Robot at this waypoint

routines is an optional array of routine that can be used to create sub-toolpaths which can be reused across your toolpath. Each routine contains the following properties:

  • name: a string identifiying a routine uniquely
  • timeline: an array following the exact same format as the toolpath's timeline (see above), note: recursion is currently not allowed (i.e. a routine cannot call itself or another routine which ends up calling it)

Example

{
  "metadata": {
    "version": 2,
    "default_max_speed": 1,
    "next_label_id": 4,
    "analog_modes": {"i0": "voltage", "i1": "voltage", "o0": "voltage", "o1": "voltage"},
    "payload": 0
  },
  "timeline": [
    {"type": "home", "waypoint_id": 0},
    {"type": "trajectory", "trajectory": "joint_space", "waypoint_id": 1, "time": 2},
    {"type": "trajectory", "trajectory": "joint_space", "waypoint_id": 2}
  ],
  "waypoints": [
    {"label_id": 1, "joints": [0, 0, 0, 0, 0, 0]},
    {"label_id": 2, "joints": [0, 1, 0, 1, 0, 0]},
    {"label_id": 3, "joints": [1, 1, 0, 1, 0, 1]}
  ]
}

See more examples in the corresponding section

Trajectory

A trajectory is the JSON representation of the setpoints that the Robot will follow to execute a toolpath. It is an array containing several objects representing either segments to move from one waypoint to another or other information.

error is a string explaining an error encountered during generation of the trajectory, it can be completely absent. If it is present, it could either be a soft error (timeline is present but invalid) or a hard error (timeline is completely absent).

duration is a float representing the approximate time in seconds it would take the robot to execute that motion. It is only present when there is no error.

timeline is an array representing a list of actions to execute to complete the toolpath, it is pretty close to the one from the toolpath. Each action has different properties, here is the list sorted by type:

  • segment: the result of the corresponding trajectories from the toolpath

    • result: a boolean representing if every setpoint is valid
    • setpoints: an array of setpoint, each containing:

      • result: a string, "success" if the setpoint is valid, "error" otherwise
      • error: a string representing a motion error, only if result is "error"
      • joints: an array of float representing the joint angles of the Robot at this setpoint
    • waypoints: an array of integers corresponding to the index in the waypoints array that the Robot is moving from/to/through (an integer of -1 express a grid-waypoint)

  • output: exactly the same as in toolpath

  • wait: exactly the same as in toolpath
  • grid: the result of the corresponding grid from the toolpath

    • iterations: an array of actions (can contain the same actions as the root timeline) for every iteration of the grid
  • if: the result of the corresponding if from the toolpath, with the same properties

  • restart: exactly the same as in toolpath
  • call-routine: the result of the corresponding call-routine from the toolpath

    • enter: follows the same format as segment, represent the transition from the current timeline to the first point of the routine
    • routine: the name of the associated routine (same as in toolpath)
    • exit: follows the same format as segment, represent the transition from the last point of the routine to the current timeline

routines is an array representing the same information as timeline but for each routine contained in the corresponding toolpath. It will be absent if the toolpath had no routines provided. Each element follow this format:

  • name: same as in toolpath
  • timeline: follows the same format as timeline above

Example

{
  "trajectory":{
    "error":"Issue when calculating setpoints in segment 2",
    "timeline":[
      {
        "type":"segment",
        "result":true,
        "waypoints":[0,1],
        "setpoints":[
          {"result":"success","joints":[0,0,0,0,0,0]},
          {"result":"success","joints":[0,0.015708419,0,0.015708419,0,0]},
          {"result":"success","joints":[0,0.06184666,0,0.06184666,0,0]},
          {"result":"success","joints":[0,0.13551569,0,0.13551569,0,0]},
          {"result":"success","joints":[0,0.2320866,0,0.2320866,0,0]},
          {"result":"success","joints":[0,0.3454915,0,0.3454915,0,0]},
          {"result":"success","joints":[0,0.46860474,0,0.46860474,0,0]},
          {"result":"success","joints":[0,0.59369063,0,0.59369063,0,0]},
          {"result":"success","joints":[0,0.7128897,0,0.7128897,0,0]},
          {"result":"success","joints":[0,0.818712,0,0.818712,0,0]},
          {"result":"success","joints":[0,0.9045085,0,0.9045085,0,0]},
          {"result":"success","joints":[0,0.9648882,0,0.9648882,0,0]},
          {"result":"success","joints":[0,0.99605733,0,0.99605733,0,0]},
          {"result":"success","joints":[0,1,0,1,0,0]}
        ]
      },
      {
        "type":"segment",
        "result":false,
        "waypoints":[1,2],
        "setpoints":[
          {"result":"success","joints":[0,1,0,1,0,0]},
          {"result":"error","error":"ik_failure","joints":[0,0,0,0,0,0]}
        ]
      }
    ]
  }
}

Listing

This endpoint allows you to list your toolpaths stored on this Robot. Note that this list is "light", i.e. it doesn't include the toolpath representation nor the trajectory as these informations can be heavy on calculation and bandwidth. Note that the hash of every toolpath is included, this allows you to know which toolpath is currently loaded.

Request

GET /api/v1/toolpaths

Payload

NONE

Reply

{
  "toolpaths":[
    {"id":1,"name":"First","hash":"ff69273707141f6521d728c153bf76a4b2995b46d83dcab8cda0b15918e53751"},
    {"id":2,"name":"Two","hash":"6bfcb6c5681d9f6419de309da99bd826b8558d25e42a98511e85aad92a9b1d88"},
    {"id":3,"name":"Interpolation","hash":"f75081fc37db3c456b2694332d3bfd35276fb1034cb6bf711c69ad5cdea46e02"},
    {"id":4,"name":"Linear + Passthrough","hash":"c61d9270d114b0a0936e1f2390cda019b1910674b14e605604b7d9ee9e891267"},
    {"id":5,"name":"I/O + Wait","hash":"17af116c6398f79e628cdaa6318e79f5985cbde3c65949eab27044c9cd105b9d"},
    {"id":6,"name":"Branches","hash":"ffda317a353f0508e13df4b26f8a507cfd92c6a82f0b688a3d42048032b2a288"},
    {"id":7,"name":"Grid","hash":"32a7cdd5db708c6433b0a89729b3f07c6ec5780ec73feb31f6d741b29021947a"}
  ]
}

or an error.

Creating

This endpoint allows you to create a new toolpath using a name and a toolpath representation. Note that the hash of the toolpath is included, this allows you to know which toolpath is currently loaded.

Request

POST /api/v1/toolpaths

Payload

{
  "name": "New toolpath",
  "toolpath": TOOLPATH_OBJ
}

where TOOLPATH_OBJ is a valid toolpath.

Reply

{
  "status":"toolpath created",
  "toolpath":{
    "id":8,
    "name":"New toolpath",
    "hash":"60fd8f0f0f64cef2686291f215b3d12242d4a77c56503e479d293414a5004732"
  }
}

or an error.

Retrieving

This endpoint allows you to retrieve the toolpath representation of a given toolpath. Note that the hash of the toolpath is included, this allows you to know which toolpath is currently loaded.

Request

GET /api/v1/toolpaths/TOOLPATH_ID

where TOOLPATH_ID is an integer representing the identifier of the toolpath, it is given when listing toolpaths or creating a new toolpath.

Payload

NONE

Reply

{
  "toolpath":{
    "id":8,
    "name":"test1",
    "hash":"634b027b1b69e1242d40d53e312b3b4ac7710f55be81f289b549446ef6778bee",
    "toolpath":TOOLPATH_OBJ
  }
}

where TOOLPATH_OBJ is a valid toolpath representation.

or an error.

Building

This endpoint allows you to retrieve the toolpath representation and trajectory of a given toolpath. Note that the hash of the toolpath is included, this allows you to know which toolpath is currently loaded.

Request

GET /api/v1/toolpaths/TOOLPATH_ID/build

where TOOLPATH_ID is an integer representing the identifier of the toolpath, it is given when listing toolpaths or creating a new toolpath.

Payload

NONE

Reply

{
  "toolpath":{
    "id":8,
    "name":"test1",
    "hash":"634b027b1b69e1242d40d53e312b3b4ac7710f55be81f289b549446ef6778bee",
    "toolpath":TOOLPATH_OBJ,
    "trajectory":TRAJECTORY_OBJ
  }
}

where TOOLPATH_OBJ is a toolpath and TRAJECTORY_OBJ is a trajectory. This may contain trajectory errors.

or an request error.

Updating

This endpoint allows you to update an existing toolpath. Note that the hash of the toolpath is included, this allows you to know which toolpath is currently loaded.

Request

PUT /api/v1/toolpaths/TOOLPATH_ID

where TOOLPATH_ID is an integer representing the identifier of the toolpath, it is given when listing toolpaths or creating a new toolpath.

Payload

{
  "name": "test2",
  "toolpath": TOOLPATH_OBJ
}

Reply

{
  "status":"toolpath updated",
  "toolpath":{
    "id":8,
    "name":"test2",
    "hash":"7d6fd7774f0d87624da6dcf16d0d3d104c3191e771fbe2f39c86aed4b2bf1a0f"
  }
}

or an error.

Deleting

This endpoint allows you to delete a given toolpath. Note that the hash of the toolpath is included, this allows you to know which toolpath is currently loaded.

Request

DELETE /api/v1/toolpaths/TOOLPATH_ID

where TOOLPATH_ID is an integer representing the identifier of the toolpath, it is given when listing toolpaths or creating a new toolpath.

Payload

NONE

Reply

{
  "status":"toolpath deleted",
  "toolpath":{
    "id":8,
    "name":"test2",
    "hash":"7d6fd7774f0d87624da6dcf16d0d3d104c3191e771fbe2f39c86aed4b2bf1a0f"
  }
}

or an error.

Using

While most of these endpoints deal with creating, retrieving, deleting toolpaths, this one doesn't change the actual database of toolpaths but select one to be used by the Robot. By using (or if you like, selecting) a toolpath, the Robot will calculate the motion, preload it into memory and will be able to replay it when asked (see controls).

Note that because there can only be one selected/used toolpath at the same time, this endpoint requires the lock to be held. As the toolpath is compiled into setpoints, this operation can take a while.

Request

POST /api/v1/toolpaths/TOOLPATH_ID/use

where TOOLPATH_ID is an integer representing the identifier of the toolpath, it is given when listing toolpaths or creating a new toolpath.

Payload

NONE

Reply

{
  "event":{
    "details":"Toolpath uploaded",
    "name":"EVENT_STATUS"
  }
}

or an error.

Unsaved actions

All the previous endpoints dealt with "saved" toolpaths that are actually stored in the Robot. These following ones allow you to interact with the Robot without saving anything in the database.

Sharing

This endpoint allows you to share a given toolpath with another user. Note that the hash of the toolpath is included, this allows you to know which toolpath is currently loaded.

Request

POST /api/v1/toolpath/share

Payload

{
  "name":"cool toolpath",
  "user_id":USER_ID,
  "toolpath":TOOLPATH_OBJ
}

where USER_ID is a valid user unique identifier (which can be retrieved using Users' listing), it describes the user with which you want to share a toolpath and TOOLPATH_OBJ is a valid toolpath.

Reply

{
  "status":"toolpath shared",
  "toolpath":{
    "id":-1,
    "name":"cool toolpath",
    "hash":"921c393922fcaa50325e0888089a8cff9362f8ae501b43444a7a80667f8553c0",
    "sharer":USER_ID
  }
}

where USER_ID is the user identifier provided in the payload.

or an error.

Calculating

This endpoint corresponds to the Building one, it allows you to retrieve the trajectory of a given toolpath's toolpath. Note that the hash of the toolpath is included, this allows you to know which toolpath is currently loaded.

Request

PUT /api/v1/toolpath/calc

Payload

{
  "toolpath":TOOLPATH_OBJ
}

where TOOLPATH_OBJ is a valid toolpath.

Reply

{
  "toolpath":{
    "hash": "7f51b4fb44dbc72708fac0a474600c2e9d8af4ce3a8b8f1680330454f6a8d68f",
  },
  "trajectory":TRAJECTORY_OBJ
}

where TRAJECTORY_OBJ is a valid trajectory.

or an error.

Using

This endpoint corresponds to the Using one, it allows you to select a toolpath by just giving a toolpath. The same notes about running, locking and compiling apply.

Request

POST /api/v1/toolpath/use

Payload

{
  "name":"test toolpath",
  "toolpath":TOOLPATH_OBJ
}

where TOOLPATH_OBJ is a valid toolpath. Note that the name argument is optional, if provided, it will be displayed as the uploaded toolpath's name (and available through control.toolpath_name using the API).

Reply

{
  "event":{
    "details":"Toolpath uploaded",
    "name":"EVENT_STATUS"
  }
}

or an error.

Migrating

From now and then we may change the format of a toolpath to allow new use-cases, some of these changes may break compatibility. This endpoint allows you to migrate a given toolpath in order to get the latest format. Note that on breaking changes, the robot will still migrate your toolpath but make changes that may affect the behavior of the toolpath, this changes will be listed so you can adapt the resulting toolpath accordingly. The hash of the toolpath is also included.

See here to learn more about the changes between each version.

Request

PUT /api/v1/toolpath/migrate

Payload

{
  "toolpath":TOOLPATH_OBJ
}

where TOOLPATH_OBJ is a valid toolpath from an older version.

Reply

{
  "toolpath":{
    "hash": "7f51b4fb44dbc72708fac0a474600c2e9d8af4ce3a8b8f1680330454f6a8d68f",
    "toolpath":TOOLPATH_OBJ
  },
  "breaking_changes":BREAKING_CHANGES_LIST
}

where TOOLPATH_OBJ is a valid toolpath with the latest format, and BREAKING_CHANGES_LIST is an array of string containing human-readable explanations of every potential breaking change that was applied.

or an error.

Version changes

This section lists the changes between each version to help you port your toolpath or generation code.

From no version (version 1) to version 2

The toolpath version must now be supplied in the version property of the metadata in a TOOLPATH_OBJ (the latest version is 2).

The default_velocity (in metadata) and velocity (in trajectory and grid-waypoint) were replaced by default_max_speed and max_speed respectively. Previously, when using velocity (or by default), the robot would calculate the maximum speed on each segment and use velocity as a factor to determine the final speed, e.g. if a segment could go as fast as 1m/s and the velocity was 0.7, the final speed would be 0.7m/s. This system was a bit confusing as a given velocity would mean different things depending on the segment but also didn't relate well to the physical world. Therefore it was replaced by max_speed which describes the maximum speed in m/s that the robot end-effector is allowed to reach on a given segment.

When migrating toolpaths, the previous velocity is transformed into max_speed by a factor of 1.5 (e.g. a velocity of 0.7 becomes a max_speed of 1.05). This transformation is a guess and will probably result in a toolpath with different speeds on each segment. We therefore recommend caution when using these new toolpaths.

The duration field of the time condition usable in wait element is now expressed in seconds instead of milliseconds. This value cannot be 0 anymore.

The time setting for trajectory and grid-waypoint cannot be 0 anymore.

The waypoints label field cannot be explicitely specified as empty string anymore.

The metadata object now supports two new properties:

  • payload: which allows to specify a payload for the whole toolpath (improves in-flight control)
  • tcp_config: (optional) which allows you to specify the offsets, rotations and radius of the tool attached to the robot end-effector

JSON examples

This section contains a few examples of toolpaths.

Interpolation

{
  "metadata": {
    "version": 2,
    "default_max_speed": 1,
    "next_label_id": 5,
    "analog_modes": {"i0": "voltage", "i1": "voltage", "o0": "voltage", "o1": "voltage"},
    "payload": 0
  },
  "waypoints": [
    {"label_id": 1, "joints": [0, 0.5235988, -1.7453293, 0, -1.9198622, 0]},
    {"label_id": 2, "joints": [0, 1.0150836, 0.20450093, 0, -1.9198622, 0]},
    {"label_id": 3, "joints": [-1.8723892, 1.0150836, -1.555968, 0, -1.9198622, 0]},
    {"label_id": 4, "joints": [-0.6408849, 1.0150836, -2.3186321, 0, -1.9198622, 0]}
  ],
  "timeline": [
    {"type": "home", "waypoint_id": 0},
    {"type": "trajectory", "trajectory": "joint_space", "waypoint_id": 1},
    {"type": "trajectory", "trajectory": "joint_space", "waypoint_id": 2},
    {"type": "trajectory", "trajectory": "joint_space", "waypoint_id": 3},
    {"type": "trajectory", "trajectory": "joint_space", "waypoint_id": 0}
  ]
}

Linear + Passthrough

{
  "metadata": {
    "version": 2,
    "default_max_speed": 1,
    "next_label_id": 7,
    "analog_modes": {"i0": "voltage", "i1": "voltage", "o0": "voltage", "o1": "voltage"},
    "payload": 0
  },
  "waypoints": [
    {"label_id": 1, "joints": [0, 0.5235988, -1.7453293, 0, -1.9198622, 0]},
    {"label_id": 2, "joints": [0.7246584, 0.034853294, -1.3462932, -1.7802324e-07, -1.8301524, 0.72465837]},
    {"label_id": 3, "joints": [-0.37476024, 0.9888687, -1.9834933, 2.8026742e-08, -2.146968, -0.37476024]},
    {"label_id": 4, "joints": [-0.7830396, 0.4468874, -2.087778, 1.5003569e-07, -1.5007017, -0.7830396]},
    {"label_id": 5, "joints": [0.4626438, 0.2402735, -2.112353, 1.3963421e-07, -1.2695131, 0.4626438]},
    {"label_id": 6, "joints": [0.78213555, 0.29602012, -2.1583045, 1.3130983e-07, -1.2793082, 0.7821356]}
  ],
  "timeline": [
    {"type": "home", "waypoint_id": 0},
    {"type": "trajectory", "trajectory": "linear", "waypoint_id": 2},
    {"type": "trajectory", "trajectory": "linear", "waypoint_id": 3},
    {"type": "trajectory", "pass_through": true, "waypoint_id": 4},
    {"type": "trajectory", "trajectory": "spline", "waypoint_id": 5},
    {"type": "trajectory", "trajectory": "linear", "waypoint_id": 1},
    {"type": "trajectory", "trajectory": "linear", "waypoint_id": 0}
  ]
}

I/O + Wait

{
  "metadata": {
    "version": 2,
    "default_max_speed": 1,
    "next_label_id": 5,
    "analog_modes": {"i0": "voltage", "i1": "voltage", "o0": "voltage", "o1": "voltage"},
    "payload": 0
  },
  "waypoints": [
    {"label_id": 1, "joints": [0, 0.5235988, -1.7453293, 0, -1.9198622, 0]},
    {"label_id": 2, "joints": [0.8808525, -0.34430662, -0.9284578, -4.6631334e-09, -1.8688283, 0.8808525]},
    {"label_id": 3, "joints": [1.5390545, 0.21697286, -1.5133435, 6.8972117e-09, -1.8452221, 1.5390545]},
    {"label_id": 4, "joints": [-2.4881413, 0.2801666, -1.5664449, 2.7822468e-08, -1.8553144, 3.1321232]}
  ],
  "timeline": [
    {"type": "home", "waypoint_id": 0},
    {"type": "output-set", "io": {"location": "base", "type": "digital", "index": 0}, "value": false},
    {"type": "wait", "condition": {
      "type": "time", "duration": 5000
    }},
    {"type": "trajectory", "trajectory": "linear", "waypoint_id": 1},
    {"type": "trajectory", "trajectory": "joint_space", "waypoint_id": 2},
    {"type": "output-set", "io": {"location": "base", "type": "digital", "index": 0}, "value": true},
    {"type": "wait", "condition": {
      "type": "input", "io": {"location": "base", "type": "digital", "index": 0}, "value": true
    }},
    {"type": "trajectory", "trajectory": "linear", "waypoint_id": 2},
    {"type": "trajectory", "pass_through": true, "waypoint_id": 3},
    {"type": "trajectory", "trajectory": "joint_space", "waypoint_id": 0}
  ]
}

If

{
  "metadata": {
    "version": 2,
    "default_max_speed": 1,
    "next_label_id": 6,
    "analog_modes": {"i0": "voltage", "i1": "voltage", "o0": "voltage", "o1": "voltage"},
    "payload": 0
  },
  "waypoints": [
    {"label_id": 1, "joints": [-2.9369467e-12, 0.4102193, -1.666564, -1.4284795e-17, -1.8852477, -2.9369755e-12]},
    {"label_id": 2, "joints": [0.2830496, -0.044686932, -1.2665379, -8.2055884e-08, -1.8303678, 0.2830496]},
    {"label_id": 3, "joints": [0.2830496, -0.04131393, -1.78083, -8.1780456e-08, -1.319449, 0.2830496]},
    {"label_id": 4, "joints": [-0.53279847, -0.27620706, -1.5215058, -4.5274876e-07, -1.3438802, -0.53279835]},
    {"label_id": 5, "joints": [0.69924986, -0.7378929, -0.3964239, -8.6449575e-08, -2.0072758, 0.69924986]}
  ],
  "timeline": [
    {"type": "home", "waypoint_id": 0},
    {"type": "trajectory", "trajectory": "joint_space", "waypoint_id": 1},
    {"type": "if", "branches": [
      {"condition": {
        "type": "input", "io": {"location": "base", "type": "analog", "index": 0}, "value": 0.5, "operator": "equal"
      }, "timeline": [
        {"type": "trajectory", "trajectory": "joint_space", "waypoint_id": 4},
        {"type": "trajectory", "trajectory": "joint_space", "waypoint_id": 4},
        {"type": "restart"}
      ]},
      {"condition": {
        "type": "input", "io": {"location": "base", "type": "analog", "index": 0}, "value": 0.25, "operator": "equal"
      }, "timeline": [
        {"type": "trajectory", "trajectory": "joint_space", "waypoint_id": 2},
        {"type": "trajectory", "trajectory": "joint_space", "waypoint_id": 3}
      ]}
    ]},
    {"type": "trajectory", "trajectory": "joint_space", "waypoint_id": 0}
  ]
}

Grid

{
  "metadata": {
    "version": 2,
    "default_max_speed": 1,
    "next_label_id": 6,
    "analog_modes": {"i0": "voltage", "i1": "voltage", "o0": "voltage", "o1": "voltage"},
    "payload": 0
  },
  "waypoints": [
    {"label_id": 1, "joints": [0, 0.5235988, -1.7453293, 0, -1.9198622, 0]},
    {"label_id": 2, "joints": [0.35769856, 0.42620432, -1.6781543, -1.3969468e-08, -1.8896427, 0.35769856]},
    {"label_id": 3, "joints": [0.26869485, -0.07519664, -1.2348145, -6.9964107e-10, -1.8315814, 0.26869485]},
    {"label_id": 4, "joints": [0.46470055, -0.25279972, -1.0379537, -1.0726533e-08, -1.8508393, 0.46470052]},
    {"label_id": 5, "joints": [1.1476622, 0.8879967, -1.9438496, 2.3310825e-07, -2.0857406, 1.1476623]}
  ],
  "timeline": [
    {"type": "home", "waypoint_id": 0},
    {"type": "grid", "w0": 2, "wx": 1, "wy": 3, "cols": 5, "rows": 4, "timeline": [
      {"type": "grid-waypoint", "time": 3},
      {"type": "trajectory", "trajectory": "linear", "waypoint_id": 4}
    ]},
    {"type": "trajectory", "trajectory": "joint_space", "waypoint_id": 0}
  ]
}

Routines

{
  "metadata": {
    "version": 2,
    "default_max_speed": 1,
    "next_label_id": 5,
    "analog_modes": {"i0": "voltage", "i1": "voltage", "o0": "voltage", "o1": "voltage"},
    "payload": 0
  },
  "waypoints": [
    {"label_id": 1, "joints": [0, 0.5235988, -1.7453293, 0, -1.9198622, 0]},
    {"label_id": 2, "joints": [0, 1.0150836, 0.20450093, 0, -1.9198622, 0]},
    {"label_id": 3, "joints": [-1.8723892, 1.0150836, -1.555968, 0, -1.9198622, 0]},
    {"label_id": 4, "joints": [-0.6408849, 1.0150836, -2.3186321, 0, -1.9198622, 0]}
  ],
  "timeline": [
    {"type": "home", "waypoint_id": 0},
    {"type": "call-routine", "routine": "move"},
    {"type": "trajectory", "trajectory": "joint_space", "waypoint_id": 0}
  ],
  "routines": [
    {
      "name": "move",
      "timeline": [
        {"type": "trajectory", "trajectory": "joint_space", "waypoint_id": 1},
        {"type": "trajectory", "trajectory": "joint_space", "waypoint_id": 2},
        {"type": "trajectory", "trajectory": "joint_space", "waypoint_id": 3}
      ]
    }
  ]
}