Servo Speed icon Servo Speed Adjust servo/PWM speed (0-20) between two positions to quickly experiment and tune motion; select board/port; settings aren't saved. Try it →
Asked

Dialogflow Driving Sphero Reliably

Windows 11 Pro, ARC 2024.05.xx. I’ve got a Sphero (SPRK+) paired over Bluetooth and the Sphero Movement Panel works great for manual driving. I’m now layering in the DialogFlow robot skill so I can say things like "forward for two seconds" or "spin left for one second" and have ARC handle timed moves.

Setup details:

  • DialogFlow skill is configured with my Google service account JSON and returns intents correctly in its console.
  • I’m using ARC’s Speech Recognition to capture voice to $Speech, then sending it to DialogFlow with:
ControlCommand("DialogFlow", "Send", $Speech)
  • In the DialogFlow skill, I’m using the "Script to Execute On Response" to read the global vars it publishes (intent name and parameters) and call Movement Panel commands. The plan is basically: Stop(), set speed, Forward()/Left(), Sleep(durationMs), Stop().

What I’m running into:

  1. Occasionally the On Response script fires twice for a single utterance, so Sphero repeats the same move back-to-back.
  2. If I use DialogFlow’s @sys.duration, the parameter often comes through as a string like "2s" or "2.0 sec", which makes Sleep() math messy. Switching to @sys.number helps, but then I lose units and must hardcode seconds.
  3. Network round-trip adds ~500-1500 ms before the command executes; during that delay Sphero may continue a prior motion. Prepending Stop() helps but causes a visible jerk.

Is there a recommended ARC pattern or sample project for consuming DialogFlow intents in the On Response script to drive the Sphero Movement Panel with precise, time-limited moves, including debouncing duplicate triggers and reliably parsing numeric parameters?



Related Hardware (view all EZB hardware)
Sphero by Sphero
Control the Bluetooth Sphero with Synthiam ARC to add speech recognition, scripting and PandoraBot AI via the Sphero Movement Panel.
Bluetooth
Servos
Camera
Audio
UART
I2C
ADC
Digital

Related Robot Skills (view all robot skills)
Dialogflow by Google
Add Google DialogFlow NLP to ARC: conversational intents, parameter prompts, scripted responses, service-account setup and programmatic robot control.
Control Sphero via Bluetooth in ARC. Detects two COM ports (one connects); requires deleting and re-pairing after disconnects or reboots.

ARC Pro

Upgrade to ARC Pro

Don't limit your robot's potential – subscribe to ARC Pro and transform it into a dynamic, intelligent machine.

Author Avatar
PRO
Canada
Twitter YouTube GitHub
#1  

Yes - the most reliable pattern in ARC is to treat DialogFlow as an intent parser only, then have a small script layer do the movement in a controlled way.

1) Use a numeric parameter, not @sys.duration

For timed motion, I recommend:

  • @sys.number for the amount
  • a separate entity or slot for the unit if you want "seconds" vs "milliseconds"

That avoids DialogFlow returning mixed strings like "2s" or "2.0 sec".

If you only care about seconds, just use @sys.number and interpret it as seconds in your ARC script.


2) Debounce duplicate DialogFlow responses

If the On Response script is firing twice, add a simple guard variable in ARC.

Example pattern:

var now = new Date().getTime();
var last = parseInt(getVar("$LastDialogFlowMs", "0"));

if ((now - last) < 400) {
  print("Ignoring duplicate DialogFlow response");
  return;
}

setVar("$LastDialogFlowMs", now.toString());

That will ignore repeats within 400 ms.
You can adjust the window if needed.


3) Move first, stop only once, and avoid extra stop calls

For Sphero, a clean sequence is:

  • set speed
  • start movement
  • sleep for the requested time
  • stop

If you’re seeing a jerk from a pre-stop, that’s usually because the robot is already moving and then gets interrupted. In most cases, it’s better to only stop once at the end unless you are intentionally canceling an in-progress command.


Example ARC script for DialogFlow response

This assumes:

  • $APIIntent contains the intent name
  • $APIComplete is true when fulfillment is complete
  • $APIParameters[0] = direction
  • $APIParameters[1] = number of seconds
var intent = getVar("$APIIntent");
var complete = getVar("$APIComplete");

if (intent != "move.direction.time") {
  return;
}

if (!complete) {
  print(getVar("$APIResponse"));
  return;
}

// Debounce duplicate callbacks
var now = new Date().getTime();
var last = parseInt(getVar("$LastDialogFlowMs", "0"));

if ((now - last) < 400) {
  print("Duplicate intent ignored");
  return;
}

setVar("$LastDialogFlowMs", now.toString());

var direction = getVar("$APIParameters[0]").toLowerCase();
var seconds = parseFloat(getVar("$APIParameters[1]"));

if (isNaN(seconds) || seconds <= 0) {
  print("Invalid time parameter");
  return;
}

var ms = Math.round(seconds * 1000);

print("Direction: " + direction + ", time: " + ms + "ms");

Movement.stop();
sleep(100);

if (direction == "forward") {
  Movement.forward();
} else if (direction == "reverse") {
  Movement.reverse();
} else if (direction == "left") {
  Movement.left();
} else if (direction == "right") {
  Movement.right();
} else {
  print("Unsupported direction: " + direction);
  Movement.stop();
  return;
}

sleep(ms);
Movement.stop();

For spin left / spin right

If you want "spin left for one second", I’d suggest making a separate intent like:

  • spin.direction.time

Then map:

  • "left" -> Movement.left()
  • "right" -> Movement.right()

If your Sphero movement skill has a specific "spin" behavior exposed through its movement panel, use that command instead. Otherwise, the left/right turn logic above is usually the simplest ARC pattern.


About the latency

That 500-1500 ms round-trip is normal when you wait on the cloud intent result. A few ways to reduce the impact:

  1. Use DialogFlow only to determine intent
  2. Keep the Sphero motion logic entirely local in ARC
  3. Avoid extra waits in the script
  4. Use a short debounce window
  5. If you need near-instant response, consider using Speech Recognition directly to script for the most common commands and reserve DialogFlow for more flexible phrases

That last option is often the best user experience:

  • Speech Recognition for fast commands like forward/stop/left/right
  • DialogFlow for more complex conversation or ambiguous phrases

Best practice for parsing parameters

If you want robust numeric parsing, do this:

var raw = getVar("$APIParameters[1]");
var seconds = parseFloat(raw);

If you ever do want to support strings like "2 sec" or "2.5 seconds", you can strip text first:

var raw = getVar("$APIParameters[1]").toLowerCase();
raw = raw.replace("seconds", "");
raw = raw.replace("second", "");
raw = raw.replace("sec", "");
raw = raw.trim();

var seconds = parseFloat(raw);

But again, @sys.number is cleaner.


ARC config tip

You can place this script in the DialogFlow skill’s config menu:

  1. Open the kebab menu / three lines on the DialogFlow skill
  2. Choose Config
  3. Edit the Script to Execute On Response

That keeps the parsing and movement logic in one place.


Helpful references


My recommendation for your project

For reliability, I’d use this structure:

  • Speech Recognition captures phrase
  • ControlCommand("DialogFlow", "Send", phrase)
  • DialogFlow returns only the intent/parameters
  • ARC script:
    • debounces
    • validates intent
    • parses numeric seconds
    • issues one movement command
    • sleeps locally
    • stops once

If you want, I can help you write a clean DialogFlow intent handler for:

  • forward for two seconds
  • reverse for three seconds
  • spin left for one second
  • stop

with a single reusable ARC JavaScript script.


I am a customer support GPT-powered AI and still learning. If you have doubts about my response, please use the support documentation to verify my answer.