Ubtech Alpha 1 Bluetooth icon Ubtech Alpha 1 Bluetooth Bluetooth control for UBTech Alpha1 servos via ARC: map Vx to servo IDs, enable servos, and integrate with ARC movement & LEDs. Try it →
Asked
ScriptStartWait Delay on ADC4

Scriptstartwait Delay On ADC4

I need a little help with timing in a JavaScript script I have running in my robot. It works great but there is one feature that I'd like to speed up. Here's what it is and what I need:

The below script that I attached polls 7 different ADC ports every 600ms on an EZBv4. Momentary buttons are attached to each of these watched ports. When one of the 7 monetary buttons are pushed and the voltage changes on its attached ADC port another script will trigger and an action will happen.

One of the sections of this script that watches these ADC ports and buttons starts several different Weather report scripts in itself, one different script after the other when this one particular momentary button is pushed. So to be clear, the first button push will give me the local temperature, the second push will give me what the actual temp feels like, the third will give me the humidity and so on. The timing of when the next button push is available is accomplished using the "ScriptStartWait" command. So, as I understand it, this command pauses the parent script calling the other child script until the "System" reports that that called child script has completed. Only then will the parent script unpause and be able to recognize the next button push to run the next script in this section.

My issue is the amount of time it takes for the next button push to be available (only in this one section using the "ScriptStartWait" method). After I push the button and the child script runs it takes at least 3 or 4 seconds for the next button push to become available after the child script ends. I'd like to get this pause shorter so the next push would be available almost right away. As is I need to wait and guess when I can push this button to hear the next step in the weather report.

Oh, also, this section also has a timer that resets the sequence back to the start if I don't push this button again within one minute

I've ran this through the ARC Script agent and it tried to adjust timing but it just messed up the script. I think the issue is using the ScriptStartWait" method. Is there any way to adjust when the system releases and unpauses the parent script thus making the next button push available? Is there a different way to write this section of the script that would let me push this button as soon as the child script completes? The timing in the rest of the script watching the other buttons is perfect.

The whole script is attached below. The section I'm referring to is labeled // ==================== Chest Button: Alpha 202, ADC4- (One button Push Each: Current Temp, Feels Like, Humidity and Wind Speed) ====================

// Polls ADC1-ADC7 only. ADC0 is handled by Script A.

var adcPorts = [1, 2, 3, 4, 5, 6, 7];
var threshold = 170;
var pollMs = 600;
var debounceMs = 150;
var ezbIndex = 0;

// Map ADC port number -> action function
var actions = [];

// ================= Chest Button: Gamma 202, ADC1- (Power Down Robot Completely) ====================
actions[1] = function() {
  sleep(6250);
  controlCommand("Shutdown PC", "ScriptStart");
};

// ==================== Chest Button: Gamma 101, ADC2- (Personality Toggle On and Off) ====================
actions[2] = function() {
  var personality = getVar("$Personality");
  sleep(200);

  if (personality == 0) {
    turnOffPersonality();
  } else if (personality == 1) {
    turnOnPersonality();
  }
};

function turnOffPersonality() {
  controlCommand("Personality Generator", "PauseOn");
  controlCommand("Weather Loop", "ScriptStop");
  sleep(4000);
  controlCommand("Soundboard v4", "Play", "Conclusion.mp3");

  print("Personality is Off");
  setVar("$Personality", 1);
}

function turnOnPersonality() {
  controlCommand("Personality Generator", "PauseOff");
  controlCommand("Weather Loop", "ScriptStart");
  sleep(4000);
  controlCommand("Soundboard v4", "Play", "GreenAndGo.mp3");
  print("Personality is On");
  setVar("$Personality", 0);
}

// ==================== Chest Button: Vector Hold, ADC3 (Open) ====================
actions[3] = function() {
  controlCommand("Personality Generator", "PauseOn");
 // setVar("$Personality", 1); //Only uncomment if this var is not set in called script.
  sleep(5000);
  controlCommand("Soundboard 2", "Play", "not.mp3");
  sleep(600);
  controlCommand("Soundboard v4", "Play", "Active-2.mp3");
  controlCommand("Personality Generator", "PauseOff");
  //setVar("$Personality", 0); //Only uncomment if this var is not set in called script.
};

// ==================== Chest Button: Alpha 202, ADC4- (One button Push Each: Current Temp, Feels Like, Humidity and Wind Speed) ====================
var alpha202ScriptList = ["Outside Temp", "Temp Feels LIke", "Humidity", "Wind Speed"];
var alpha202Index = 0;
var alpha202LastCompleteMs = 0;
var alpha202ResetMs = 60000; // 1 minute

actions[4] = function() {
  var now = nowMs();

  // Reset sequence if more than 1 minute since last completed run
  if (alpha202LastCompleteMs > 0 && (now - alpha202LastCompleteMs) > alpha202ResetMs) {
    alpha202Index = 0;
  }

  controlCommand("Personality Generator", "PauseOn");
  controlCommand("Weather Loop", "ScriptStop");
  sleep(4750);
  
  var scriptToRun = alpha202ScriptList[alpha202Index];
  controlCommand("Time, Date & Temp", "ScriptStartWait", scriptToRun);

  alpha202LastCompleteMs = nowMs();
  alpha202Index = alpha202Index + 1;
  if (alpha202Index >= alpha202ScriptList.length) {
    alpha202Index = 0;
  }

  controlCommand("Personality Generator", "PauseOff");
  controlCommand("Weather Loop", "ScriptStart");
};

// ================ Chest Button: Bata 202, ADC5 -(Speak Time,Date and Environmental Report) ====================
actions[5] = function() {
  controlCommand("Personality Generator", "PauseOn");
  //setVar("$Personality", 1); //Only uncomment if this var is not set in called script.
  sleep(6000);
  controlCommand("Time, Date & Temp", "ScriptStart", "Time,Date,Enviroment");
};

// ==================== Chest Button: Detent +, ADC6 (Open) ====================
actions[6] = function() {
  controlCommand("Personality Generator", "PauseOn");
  //setVar("$Personality", 1); //Only uncomment if this var is not set in called script.
  sleep(5000);
  controlCommand("Soundboard 2", "Play", "not.mp3");
  sleep(600);
  controlCommand("Soundboard v4", "Play", "Active-2.mp3");
  controlCommand("Personality Generator", "PauseOff");
  //setVar("$Personality", 0); //Only uncomment if this var is not set in called script.
};

// ============ Chest Button: Vector Release, ADC7-(Run Soil Sampler & Speak Report ====================
actions[7] = function() {
  controlCommand("Personality Generator", "PauseOn");
  setVar("$Personality", 1); //Var is set because this is the control script.
  Digital.set(d0, true);
  Digital.set(d23, true, 1);
  Digital.set(d2, true);
  Digital.set(d10, true);
  sleep(2000);
  Digital.set(d23, false, 1);
  controlCommand("Leg Section", "ScriptStart", "Hip Down Full");
  sleep(6000);
  controlCommand("Leg Section", "ScriptStart", "Up with Hips");
  sleep(3500);
  controlCommand("Head Section", "ScriptStart", "Bubble Up and Down");
  sleep(250);
  Digital.set(d2, false);
  sleep(10000);
  Digital.set(d0, false);
  Digital.set(d10, false);
  controlCommand("Personality Generator", "PauseOff");
  setVar("$Personality", 0); //This Var is cleared because this is the control script.
};

var lastState = [];
var stableStart = [];

function nowMs() {
  return (new Date()).getTime();
}

print("ADC Watcher: start. Polling " + adcPorts.length + " ports every " + pollMs + " ms");

while (true) {
  try {
    for (var i = 0; i < adcPorts.length; i++) {
      var port = adcPorts[i];
      var value = ADC.get(port, ezbIndex);
      var pressed = (value >= threshold);

      if (pressed !== lastState[port]) {
        if (stableStart[port] == null || stableStart[port] == 0) {
          stableStart[port] = nowMs();
        } else {
          if (nowMs() - stableStart[port] >= debounceMs) {
            lastState[port] = pressed;
            stableStart[port] = 0;

            var t = new Date().toLocaleString();
            print(t + " ADC" + port + " state -> " + (pressed ? "PRESSED" : "RELEASED") + " val:" + value);

            if (pressed) {
              try {
                if (typeof actions[port] === "function") {
                  actions[port]();
                } else {
                  print("ADC Watcher: no action defined for port " + port);
                }
              } catch (ae) {
                print("ADC Watcher: action error: " + ae);
              }
            }
          }
        }
      } else {
        stableStart[port] = 0;
      }
    }
  } catch (e) {
    print("ADC Watcher: error reading ADC: " + e);
  }

  sleep(pollMs);
}


Related Hardware (view all EZB hardware)
EZ-B V4 by EZ-Robot
EZ-B v4/2 robot controller: dual Cortex ARM, Wi-Fi, audio/video, 24 servo/digital ports, I2C/UART, camera and Synthiam ARC control for custom robots
Wi-Fi / USB
Servos 24
Camera
Audio
UART 3
I2C
ADC 8
Digital 24

Related Robot Skills (view all robot skills)
Manage and execute multiple scripts in a single Script Manager using ControlCommand(), with Control Details showing available commands.
Script by Synthiam
Multi-language ARC Script: build, run and debug Blockly, JavaScript, EZ-Script or Python with Intellisense, run/save/load and Roboscratch support

ARC Pro

Upgrade to ARC Pro

Unlock the true power of automation and robotics by becoming a proud subscriber of Synthiam ARC Pro.

Author Avatar
PRO
Canada
Twitter YouTube GitHub
#1  

Yes - the delay is very likely coming from ScriptStartWait itself, not from the ADC polling.

What’s happening

controlCommand("Time, Date & Temp", "ScriptStartWait", scriptToRun);

means:

  • the parent script blocks
  • ARC waits for the child script to finish
  • then the parent script continues

If you’re seeing a 3-4 second gap after the child script ends, that’s usually because the parent script is still tied up in the wait/blocking behavior and then returning to the polling loop afterward.

Best fix

For this kind of "press once, run next step, be ready immediately for the next press" workflow, I’d recommend not using ScriptStartWait here.

Instead, use:

controlCommand("Time, Date & Temp", "ScriptStart", scriptToRun);

Then let the button sequence state advance independently.


Better approach for your weather sequence

You already have alpha202Index, so you can keep the sequence moving without waiting for the child script to "release" the parent.

Replace this:

controlCommand("Time, Date & Temp", "ScriptStartWait", scriptToRun);
alpha202LastCompleteMs = nowMs();

With this:

controlCommand("Time, Date & Temp", "ScriptStart", scriptToRun);
alpha202LastCompleteMs = nowMs();

That will make the parent return to monitoring much faster.


If you need the next press to happen only after speech finishes

If the goal is not "script complete" but rather "speech/audio complete", then ScriptStartWait may still not be the right tool, because child scripts can return before all audio is actually done depending on how they’re written.

A more reliable pattern is to have the child script set a status variable when it is truly finished, for example:

setVar("$WeatherStepDone", 1);

Then the parent can watch for that variable, or better yet, avoid waiting entirely and just use the button sequence index.


The cleanest fix for your case

Because your weather reports are user-initiated button steps, I’d suggest this structure:

  1. Button press triggers the next script immediately
  2. Parent increments the index right away
  3. Use a reset timeout to wrap back to 0 after 1 minute of inactivity
  4. Let the child script handle its own speech timing

That way, the next press is accepted as soon as ARC gets back to the poll loop.


Example rewrite of your Alpha 202 section

var alpha202ScriptList = ["Outside Temp", "Temp Feels Like", "Humidity", "Wind Speed"];
var alpha202Index = 0;
var alpha202LastPressMs = 0;
var alpha202ResetMs = 60000; // 1 minute

actions[4] = function() {
  var now = nowMs();

  if (alpha202LastPressMs > 0 && (now - alpha202LastPressMs) > alpha202ResetMs) {
    alpha202Index = 0;
  }

  alpha202LastPressMs = now;

  controlCommand("Personality Generator", "PauseOn");
  controlCommand("Weather Loop", "ScriptStop");
  sleep(4750);

  var scriptToRun = alpha202ScriptList[alpha202Index];
  controlCommand("Time, Date & Temp", "ScriptStart", scriptToRun);

  alpha202Index++;
  if (alpha202Index >= alpha202ScriptList.length) {
    alpha202Index = 0;
  }

  controlCommand("Personality Generator", "PauseOff");
  controlCommand("Weather Loop", "ScriptStart");
};

Why this helps

  • no blocking wait
  • next press becomes available sooner
  • reset still works after 1 minute of inactivity

One more important note

You’re polling every 600 ms, so even with a perfect script you can only detect a new press roughly every 0.6 seconds plus debounce. If you want the system to feel more responsive, consider lowering pollMs to something like:

var pollMs = 50;

or

var pollMs = 100;

That alone can make button response feel much snappier.


Recommendation

For this section, I’d try in this order:

  1. Change ScriptStartWait to ScriptStart
  2. Reduce pollMs from 600 to 100 or 50
  3. Keep your sequence index logic for the 1-minute timeout

If you want, I can also help you rewrite just the ADC4 section into a cleaner state-machine version that preserves your timing behavior and removes the wait stall entirely.

I am a customer support AI and still learning. Please verify important answers in our support documentation. For advanced AI features, use the AI Script Agent built into ARC.