virtual_controller) resolves a command string against the keyboard controller policy assigned to a digital twin and publishes the matching actuation on cyberwave/twin/{uuid}/command. The MQTT payload matches keyboard teleoperation (KeyboardTeleoperationController / useMQTTTwin.publishCommand) — nothing is hardcoded per robot; bindings come from the twin’s policy at runtime.
Palette category: Actuation. Runs on cloud (Celery MQTT) and edge (worker
client.mqtt.publish). Locomotion uses the MQTT command topic, not WebRTC; media streaming stays on separate channels.Voice-to-actuation pipeline
Inputs
Precedence: wired input mapping → node parameters.
Command matching
The node accepts either form (normalization is shared with Fuzzy Matcher):
Resolution order:
- Exact actuation (case / punctuation insensitive)
- Exact human label
- Keyboard key
- Substring containment (label inside longer STT phrase)
metadata.keyboard_bindings(actuation,label,key, optionalplaygrounddata)metadata.display_config.widgets(buttoncommand, slidercommand)- Universal keyboard policies with
supports_locomotionand no bindings → default WASD locomotion actuations (move_forward,turn_left, …)
Inspector
- Digital Twin — combobox; policy is never hardcoded in the node.
- command — wire from upstream (typically Fuzzy Matcher
match_string).
Inspector preview
When a twin is selected, the panel shows:
Use this list to verify what voice commands the pipeline can dispatch before running the workflow.
MQTT payload
Published tocyberwave/twin/{twin_uuid}/command:
Same shape as manual keyboard teleop so edge drivers and simulators consume workflow commands without special cases.
Outputs
On resolution failure the node raises an error (unknown command, missing policy, missing twin).
Execution targets
Edge workers save the resolved controller snapshot (UUID, name, metadata, parsed
entries) in process memory so repeat commands on the same twin do not re-fetch the policy every frame.
Recommended Conditional gate
Only run Virtual Controller when Fuzzy Matcher succeeded:fuzzy_matcher.match_string into virtual_controller.command on the true branch.
Dependencies
rapidfuzz is only required on the Fuzzy Matcher node upstream, not on Virtual Controller.
Full voice-pipeline matrix: Edge workflow dependencies.
Controller policy examples
Command-mode UGV policies (control_mode: "command") define bindings like:
move_forward on MQTT when the pipeline passes "Forward", "move_forward", or fuzzy-matched variants. See seeded policies in seed_controllers.py (e.g. controller:ugv-beast:v1).
Universal keyboard (controller:keyboard-locomotion:v1) has no per-asset bindings in seed data; the node uses built-in locomotion defaults when supports_locomotion is true.
Related nodes
- Twin — supplies Fuzzy Matcher
candidatesfromcontrol_actuations/control_labels - Fuzzy Matcher — maps noisy STT (uncertain string) →
match_stringfrom a source-of-truth string or array - Call Model — STT text → Fuzzy Matcher
query - Conditional — gate on
matched - Send MQTT — generic publish; Virtual Controller is purpose-built for controller actuations