Build a voice-controlled SO-101 arm with Workflows
Drive an SO-101 arm with plain English using the visual Workflow editor — no code, no VLA training. Speak a command, a model plans a sequence of poses, and the arm executes it.
Early tutorial (stub). The flow and node configuration below are complete
enough to build and test end-to-end. Screenshots and a shareable template link
will be added as the template is published.
By the end of this tutorial you’ll have an SO-101 arm that listens to a spoken
command, has a model turn it into a short sequence of poses, and executes that
sequence — built entirely in the visual Workflow editor, no scripts and no VLA
training.Prefer to build it in Python? See the SDK version:
Control an SO-101 arm with your voice.
Want a learned policy instead of a pose vocabulary? See the VLA version:
Voice-controlled pick and place.
A trained VLA generalises, but needs a dataset. This template takes the opposite
trade: you pre-teach the arm a small set of named poses for a fixed workspace,
and a model just sequences them. No training, no dataset — the fixed pose set
is your deterministic contract.
Create a workflow (SO-101 Voice Agent) and add both twins: the microphone
and the SO-101. You’ll wire nine nodes left to right; inputs are set in the
inspector — fixed values on the # tab, references to another node with the </>
expression tab using {node-name.output} syntax.
Add a second Call Model and pick an LLM or VLM. Set the Prompt to </>
(expression) and paste the pose planner below; the last line inlines the transcript.
Pose planner prompt
You are the motion planner for an SO-101 robot arm doing pick-and-place on afixed workspace. Turn the operator's request (and the workspace image, if given)into a JSON plan. No chat, no markdown, no code fences.# You may ONLY use these named steps- "open_gripper" / "close_gripper"- "home" — safe home pose- "over_object" — hover above the object to pick- "grasp" — lower onto the object- "lift" — raise the grasped object- "over_target" — hover above the drop location- "release" — lower to the drop locationYou do NOT set joint angles, coordinates, or speed. You only sequence the namedsteps. If the request is impossible with these steps or the object isn't visible,return a single {"action":"home"} step and say why in "say".# Output — exactly one JSON object{ "say": "<one short sentence>", "steps": [ {"action":"open_gripper"} ] }# Rules- 1 to 12 steps. A normal pick-and-place is: open_gripper -> over_object -> grasp -> close_gripper -> lift -> over_target -> release -> open_gripper -> home- Always open the gripper before grasping and end at "home".- NEVER invent step names. NEVER output prose outside the JSON.# ExampleRequest: "put the block in the cup"{"say":"Picking the block into the cup.","steps":[{"action":"open_gripper"},{"action":"over_object"},{"action":"grasp"},{"action":"close_gripper"},{"action":"lift"},{"action":"over_target"},{"action":"release"},{"action":"open_gripper"},{"action":"home"}]}# The operator's request"{call-model.result}"
If using a VLM, also wire image_url ← {data-source.image_url}. Leave
image_url empty for a plain LLM. Output: result = the JSON plan.
Switch to SIMULATE — voice is real, the arm runs as a 3D twin.
Confirm the arm is at zero pose and (if using a VLM) the camera streams.
Say “put the block in the cup.”
Walk Executions:
Node
Expect
Call Model (STT)
result = your words
Call Model (planner)
valid JSON pose plan
Loop
ran once per step
Fuzzy Matcher
matched = a real pose, match: true
Virtual Controller
Sent: true per step
Then test an impossible request (“make me a coffee”) → the plan degrades to
home, the arm does nothing unsafe.
Step completion / pacing. Poses take real time. Confirm each
virtual_controller command finishes before the next fires — otherwise grasp
could be sent mid-move. If your controller doesn’t queue/complete commands in
order, add a short wait step between moves. Simulation is where you catch this.
Zero-pose on attach. When a non-teleop controller attaches, the arm first
moves to zero pose with collision detection on, and queues commands during that
transition. Expect a brief pause before the first move.
Once simulation is clean, switch to LIVE to drive the physical arm. The graph
is unchanged — only the target flips. Keep an eye on it and be ready to stop.
The model never sets joint angles and never commands the arm directly. It only
sequences pre-taught poses, and every step is validated against the arm’s real
vocabulary before it moves. The model reasons; a fixed contract acts.