Work in progress: this documentation is still being written and reviewed. Check details against the source code.

Write task scripts

A task script defines an EROBS sequence in JSON. Create one in a text editor or save a sequence from the Operator GUI.

Start with the ePick example

The repository’s src/cms/tasks/demo_epick_moveto.json moves between two named joint poses. Run your first task shows how to run it with the CMS drylab configuration and mock hardware.

{
  "start_gripper": "epick",
  "poses": {
    "safe_sample_transport": [79.72, -69.5, -81.91, -117.92, -268.05, -157.15],
    "safe_tool_exchange": [152.33, -110.63, -100.17, -59.12, -270.43, -207.7]
  },
  "tasks": [
    {
      "task_type": "moveto",
      "target": "safe_sample_transport",
      "planning_type": "joint"
    },
    {
      "task_type": "moveto",
      "target": "safe_tool_exchange",
      "planning_type": "joint"
    }
  ]
}

Field

Purpose

start_gripper

Required. Declares the tool already attached and selects its initial MoveIt model.

poses

Optional. Defines named poses as six joint angles in degrees.

tasks

Required. A nonempty list of steps, each identified by task_type, in execution order.

The same three parts appear in every task script, as this annotated example shows:

Anatomy of a named-move task The complete named-move example has start_gripper none, an inline example_home pose containing six joint angles in degrees, and one moveto task whose target is example_home. Inline pose data takes priority; the parser fills missing names from the registry. If a MoveTo name remains absent, its motion stage tries an SRDF named state. These are illustrative parser inputs, not a validated robot motion. EROBS / TASK ANATOMY Anatomy of a named-move task One document declares the starting tool, named poses, and ordered work. named-move.json { "start_gripper": "none", "poses": { "example_home": [0, -90, 90, -90, -90, 0] }, "tasks": [ { "task_type": "moveto", "target": "example_home" } ] } The same pose name connects the task to its joint values. Starting tool model A key in the beamline’s grippers. Declares the already attached tool. Inline pose values Six joint angles, in degrees. This example supplies its own pose. Ordered task list One MoveTo step in this example. target is a name, not XYZ. The list must be nonempty. How a named target is resolved 1 Inline pose Use the document’s value. example_home resolves here. 2 Pose registry Fill names absent from poses. Inline values keep priority. 3 SRDF state If still absent, MoveTo tries the robot model’s named state. Illustrative parser input. Parsing does not establish reachability or collision clearance.
Open the full-size diagram

Here, epick must exist in the active beamline’s grippers configuration. Declaring it does not attach a tool. Likewise, moving to safe_tool_exchange changes the arm position; it does not perform a tool exchange.

Poses defined in the script override shared poses with the same name. Omit them to use the deployment’s pose registry. These example coordinates belong to the CMS setup; use calibrated poses for another installation.

Choose one MoveTo target

For each moveto, specify exactly one of these forms:

Form

Meaning

target

A pose defined in the script, a shared pose, or a named robot state from the SRDF.

direction and distance

A relative move in the flange frame, with distance in metres.

cartesian_target

Three values (XYZ in metres) or six (XYZ plus roll/pitch/yaw in degrees). frame_id defaults to base_link.

Do not combine target forms in one step. Relative distance must be finite and greater than zero; Cartesian coordinates must also be finite.

For example, this script requests a 10 mm move along the flange’s positive X axis from the current position:

{
  "start_gripper": "epick",
  "tasks": [
    {
      "task_type": "moveto",
      "direction": "forward",
      "distance": 0.01,
      "planning_type": "cartesian"
    }
  ]
}

The direction rotates with the flange. Check the starting pose and preview the movement before executing it. See the MoveTo reference for direction aliases, orientation defaults, and planner options.

Compose a sequence

Add task objects to tasks in the required order. Use the task inventory to find gripper, vision, tool-exchange, and pipettor operations and their fields.

Insert {"task_type": "pause"} where the operator needs to inspect the result. It waits for Resume rather than a fixed duration. A sequence containing a pause cannot be previewed as a whole.

Consecutive moveto and end_effector steps can be planned together as a batch. Vision, tool-exchange, pipettor, and pause steps separate batches. See execution controls for how this affects pausing and cancellation.

Compare previews

Preview supports only moveto and end_effector. With batching enabled, eligible steps are planned as a connected sequence. Without batching, each preview starts from the live robot state, and the GUI replaces the displayed trajectory when the next preview arrives.

In this example, the robot stays at A while targets B and C are previewed. See preview limits for details.

Why two previews may not form one sequence Assume the real robot stays at A during Dry Run and the task list requests moves to B then C. With batching enabled, one MTC task produces a connected preview A to B to C. With batching disabled, each row creates a task from live CurrentState: first A to B, then A to C. The GUI replaces its preview when a new trajectory arrives rather than queuing both previews. Execute with Dry Run cleared performs motion; after a successful first move, the live robot can be at B before the next row plans. A schematic path shows order, not physical geometry. EROBS / PREVIEW COMPARISON Why two previews may not form one sequence Same task list: move to B, then C. The real robot stays at A during Dry Run. Batching on Both moves share one MTC task. Batching off Each row creates a new MTC task. One connected preview A B C live start target 1 target 2 A → B → C The later stage continues from the earlier stage’s planned endpoint. First row A B Second row A C Both start at live CurrentState = A. The preview never moved the robot to B. What the GUI displays A new trajectory replaces the active preview; the viewer does not queue it. With batching off, A → C replaces A → B, even if its animation has not finished. Execution changes the live state Clear Dry Run, then Execute to request motion. After the first unbatched move succeeds, the robot is at B, so the next row can plan from B. Cached replay has separate eligibility checks. Schematic order only; arrows do not depict physical paths or distances.
Open the full-size diagram

Load and check the script

  1. Save the document as a .json file and open it with File → Load JSON in the GUI.

  2. Check Start Gripper, the task order, and the pose values. Loading a file does not execute it.

  3. For a supported sequence, select Dry Run, press Execute, and inspect the planned motion in 3D View or RViz.

  4. Review the Activity Log for errors and the completed-step count. Follow Preview and execute when ready to run it.

Dry Run is a GUI execution setting, not a task JSON field. Mock hardware is selected at launch; see Run your first task.

The orchestrator validates the document structure, task types, and target formats when it receives the script. That does not verify every pose name, reachability, collision clearance, or device availability; planning and execution check those later. See task execution.