Asked

Help With EZ-Script Coding

I'm working on a project with my EZ-B v4, and I need some assistance with coding the GetDigital command. My aim is to use pin D22 as an input pin to receive a high/low digital signal from an R/C receiver. The receiver uses a PWM-to-digital output device on one of its channels. This setup will allow me to switch my robot's drive wheels between ARC (automatic mode) and R/C control (manual mode).

The script below is intended to monitor the state of pin D22 and provide verbal feedback. When in Automatic Mode, ARC will control the wheels and all sensors. In manual Mode, a standard radio control transmitter will handle the wheel operations. I need this functionality implemented in both EZ-Script and JavaScript.

Here's my current EZ-Script code:

$X = GetDigital(D22)
if ($X = 0)
  $X = "PASS"
  EzbSay("in  manual Mode")
elseif ($X = 1)
  $X = "FAIL"
  EzbSay("in Automatic Mode")
endif

Could you review it and help me ensure that it performs correctly? Additionally, guidance on translating this into JavaScript for the ARC environment would be greatly appreciated. Thank you!



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)
EZB Connection by Synthiam
Connects EZ-B I/O controllers to ARC via COM or IP (5 connections). Supports init scripts, battery monitoring, TCP/EZ-Script server and serial/I2C.
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

Stay at the forefront of robot programming innovation with ARC Pro, ensuring your robot is always equipped with the latest advancements.

#73  

Athena, Im still doing some testing, but could you put back the LED for manual mode on D21 of your Robust EZB_D22 script? It always throws me off when it not on.

Author Avatar
PRO
Canada
#74  

Perfect - I added D21 LED control to the robust EZB_D22 monitor so the LED turns ON when the robot is in manual mode and OFF when in Automatic mode. The script uses the existing ezbIndex and only writes D21 when the mode actually changes (to avoid repeated writes). It also sets the LED after reconnect settle/read so it matches the announced mode.

Paste this into your Script skill (JavaScript tab), save and Start it. If your Script skill has a different title, update skillTitle. If you want the LED behavior reversed (ON for Automatic), tell me and I’ll flip it.

Updated script (JavaScript)

/*
 EZB_D22 Reliable Monitor with Manual-mode LED on D21
 - Place in a Script skill (JavaScript tab) and Start it.
 - Uses Digital.get(d22) for mode input.
 - Sets D21 HIGH when in  manual mode, LOW when in Automatic mode.
 - Sets global $Mode ("Automatic" / "Manual").
 - Debounce and settle on reconnect to avoid false announcements.
*/

var skillTitle = "EZB_D22_ConnMerge";   // change if your Script skill name is different
var ezbIndex = 0;                       // change if using another EZB index
var pollMs = 120;                       // main loop poll (ms)
var debounceMs = 300;                   // stable time to confirm change (ms)
var settleOnConnectMs = 900;            // wait after EZB reconnect before reading (ms)
var runFlagVar = "$EZB_D22_Running";    // global marker to prevent duplicates

// LED pin for  manual mode indicator (will be set HIGH for Manual)
var manualLedPin = d21; // use constant d21 (no quotes)

// Helper: prefer EZB TTS, fallback to PC
function announce(text) {
  try {
    if (EZB.isConnected(ezbIndex)) Audio.sayEZB(text, ezbIndex);
    else Audio.say(text);
  } catch (e) {
    print("announce error:" + e);
  }
}

// Map boolean to mode label
function modeFromBoolean(b) {
  return b ? "Automatic" : "Manual";
}

// Debounced read of d22. Returns true/false or null if unstable
function readDebouncedD22() {
  try {
    var a = Digital.get(d22); // constant d22 (no quotes)
    if (a === null || a === undefined) return null;
    var start = (new Date()).getTime();
    while ((new Date()).getTime() - start < debounceMs) {
      var b = Digital.get(d22);
      if (b !== a) { // unstable
        return null;
      }
      sleep(20);
    }
    return !!a;
  } catch (e) {
    print("readDebouncedD22 error:" + e);
    return null;
  }
}

// Set  manual LED: true = On (Manual), false = Off (Automatic)
function setManualLed(state) {
  try {
    // Only write when EZB is connected and state is boolean
    if (!EZB.isConnected(ezbIndex)) {
      print("setManualLed: EZB not connected, cannot set D21");
      return;
    }
    Digital.set(manualLedPin, state, ezbIndex);
    print("D21 set to " + (state ? "ON (Manual)" : "OFF (Automatic)"));
  } catch (e) {
    print("setManualLed error:" + e);
  }
}

// Prevent duplicate instances started (by Connection script)
if (getVar(runFlagVar, "0") === "1") {
  print(skillTitle + " already running. Exiting duplicate start.");
} else {
  setVar(runFlagVar, "1");
  print(skillTitle + " starting. EZB.isConnected=" + EZB.isConnected(ezbIndex));

  var lastState = null;
  var wasConnected = EZB.isConnected(ezbIndex);

  // On first start, try to read D22 right away (if connected)
  if (wasConnected) {
    sleep(200);
    var s0 = readDebouncedD22();
    if (s0 !== null) {
      lastState = s0;
      setVar("$Mode", modeFromBoolean(s0));
      setManualLed(!s0); // note: manualLed ON when mode is  manual (D22 false -> Manual)
      announce("Initial mode " + modeFromBoolean(s0) + " (D22=" + (s0 ? 1 : 0) + ").");
      print("Initial read D22=" + (s0 ? 1 : 0));
    } else {
      print("Initial D22 read unstable/null.");
    }
  }

  // Main monitor loop
  while (true) {
    try {
      var connected = EZB.isConnected(ezbIndex);

      // Handle reconnect: when connection goes disconnected -> connected
      if (!wasConnected && connected) {
        print("EZB reconnected - waiting " + settleOnConnectMs + "ms to settle.");
        sleep(settleOnConnectMs);
        var state = readDebouncedD22();
        if (state !== null) {
          if (state !== lastState) {
            lastState = state;
            setVar("$Mode", modeFromBoolean(state));
            setManualLed(!state); //  manual when state is false (D22=0)
            announce("Mode change " + modeFromBoolean(state) + " (D22=" + (state ? 1 : 0) + ").");
            print("Announced after reconnect D22=" + (state ? 1 : 0));
          } else {
            // Re-announce current mode once after reconnect and ensure LED matches
            setVar("$Mode", modeFromBoolean(state));
            setManualLed(!state);
            announce("Mode " + modeFromBoolean(state) + " (D22=" + (state ? 1 : 0) + ").");
            print("Reconnected; re-announced D22=" + (state ? 1 : 0));
          }
        } else {
          print("After reconnect: D22 unstable/null - no announcement.");
        }
      }

      // Regular polling if connected
      if (connected) {
        var s = readDebouncedD22();
        if (s !== null && lastState === null) {
          // first known read
          lastState = s;
          setVar("$Mode", modeFromBoolean(s));
          setManualLed(!s);
          announce("Initial mode " + modeFromBoolean(s) + " (D22=" + (s ? 1 : 0) + ").");
          print("First stable read D22=" + (s ? 1 : 0));
        } else if (s !== null && s !== lastState) {
          // stable change detected
          lastState = s;
          setVar("$Mode", modeFromBoolean(s));
          setManualLed(!s);
          announce("Mode change " + modeFromBoolean(s) + " (D22=" + (s ? 1 : 0) + ").");
          print("Mode changed D22=" + (s ? 1 : 0));
        }
      } else {
        // Optionally you could set LED off when disconnected,
        // but we cannot write to EZB when it's disconnected.
        //print("EZB not connected.");
      }

      wasConnected = connected;
    } catch (loopErr) {
      print("Monitor loop exception:" + loopErr);
    }
    sleep(pollMs);
  }
}

Quick testing tips

  • Manual LED test: in a quick Script skill or the Script Console run:
Digital.set(d21, true);   // turn LED on
Digital.set(d21, false);  // turn LED off
  • Confirm D21 wiring uses an appropriate resistor and common ground. If you used this LED before it should be fine.
  • If your LED is active-low (wired to Vcc through LED and port sinks to ground) tell me and I’ll invert the writes.

Note about the LED logic

  • The script assumes D22 = HIGH (true) means Automatic, LOW (false / 0) means manual (per your earlier description). The LED is turned ON for manual (i.e., when D22 is false). If you prefer the LED ON for Automatic instead, I’ll flip the setManualLed(!state) calls to setManualLed(state).

Next

  • Would you like the LED to blink briefly when mode changes (visual feedback) instead of just steady ON/OFF?
  • Do you want me to add a small file log (timestamped) whenever the mode changes so you can audit reconnects later?

Tell me which LED polarity or blink preference you want, and I’ll provide that tweak.


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.
#75  

Yes, I would like the LED on D21 to blink briefly when mode changes, and add the log file as you suggested.

Author Avatar
PRO
Canada
#76  

Great - I added the blink-on-change behavior and a timestamped log file to the robust EZB_D22 monitor. Paste the script into a Script robot skill (JavaScript tab), save and Start it. The script will:

  • Blink the D21 LED briefly whenever the mode changes.
  • Set D21 steady ON when in manual mode, OFF in Automatic mode (same behavior as before).
  • Append a timestamped line to a log file each time the mode changes, on reconnect announcements, and at script start.
  • Keep $Mode updated ("Automatic" / "Manual") so other scripts can read it.

Important: put this code in the Script skill JavaScript tab (not EZ-Script). Update file path or ezbIndex if needed. If Windows permissions block file writes, change the logFile path to a writable folder (see notes below).

Script - paste into your Script skill JavaScript tab

// EZB_D22 Monitor with D21 blink on mode change + log file
// Place in a Script skill (JavaScript tab) and Start it.
// Adjust ezbIndex, skillTitle, and logFile path if needed.

var skillTitle = "EZB_D22_ConnMerge"; // exact Script skill title
var ezbIndex = 0;                     // change if you use another EZB index
var pollMs = 120;                     // main loop interval (ms)
var debounceMs = 300;                 // stable time to confirm change (ms)
var settleOnConnectMs = 900;          // wait after EZB reconnect before reading (ms)
var runFlagVar = "$EZB_D22_Running";  // prevents duplicate instances

// LED pin for  manual mode indicator (HIGH when Manual)
var manualLedPin = d21;               // use constant d21 (no quotes)

// Logging
var logFile = "C:\\Users\\Public\\Documents\\ModeChanges.log"; // change if needed

// Blink configuration
var blinkCount = 2;
var blinkMs = 150;

// Helper: prefer EZB TTS, fallback to PC TTS
function announce(text){
  try {
    if (EZB.isConnected(ezbIndex)) Audio.sayEZB(text, ezbIndex);
    else Audio.say(text);
  } catch(e){
    print("announce error: " + e);
  }
}

// Log a timestamped message to the file and to the ARC log
function logEvent(text){
  try {
    var ts = (new Date()).toLocaleString();
    var line = ts + " - " + text;
    File.appendStringLine(logFile, line);
    print("LOG: " + line);
  } catch(e){
    print("Log write error: " + e + " (path: " + logFile + ")");
  }
}

// Map boolean D22 -> mode string
function modeFromBoolean(b){ return b ? "Automatic" : "Manual"; }

// Set the  manual LED (safe: checks EZB connected)
function setManualLed(val){
  try {
    if (EZB.isConnected(ezbIndex)){
      Digital.set(manualLedPin, val);
      print("D21 set to " + (val ? "ON" : "OFF"));
    } else {
      print("Cannot set D21 - EZB not connected");
    }
  } catch(e){
    print("setManualLed error: " + e);
  }
}

// Blink the LED count times, then set final state
function blinkManualLed(finalState){
  try {
    if (!EZB.isConnected(ezbIndex)){
      print("Cannot blink D21 - EZB not connected");
      return;
    }
    for (var i=0;i<blinkCount;i++){
      Digital.set(manualLedPin, !finalState); // flash opposite
      sleep(blinkMs);
      Digital.set(manualLedPin, finalState);
      sleep(blinkMs);
    }
    // ensure final steady state
    Digital.set(manualLedPin, finalState);
  } catch(e){
    print("blinkManualLed error: " + e);
  }
}

// Debounced read of d22. Returns true/false or null if unstable/unavailable
function readDebouncedD22(){
  try {
    var a = Digital.get(d22); // use constant d22
    if (a === null || a === undefined) return null;
    var start = (new Date()).getTime();
    while ((new Date()).getTime() - start < debounceMs){
      var a2 = Digital.get(d22);
      if (a2 === null || a2 === undefined) return null;
      if (a2 !== a) {
        // unstable
        return null;
      }
      sleep(10);
    }
    return !!a;
  } catch(e){
    print("readDebouncedD22 error: " + e);
    return null;
  }
}

// Prevent duplicate runs started by Connection scripts
if (getVar(runFlagVar, "0") === "1"){
  print(skillTitle + " already running. Exiting duplicate start.");
} else {
  setVar(runFlagVar, "1");
  print(skillTitle + " starting. EZB.isConnected=" + EZB.isConnected(ezbIndex));
  logEvent(skillTitle + " script started");

  var lastState = null; // true = Automatic (D22 high), false =  manual (D22 low)
  var wasConnected = EZB.isConnected(ezbIndex);

  // On first start, try an initial read if connected
  if (wasConnected){
    sleep(200);
    var s0 = readDebouncedD22();
    if (s0 !== null){
      lastState = s0;
      setVar("$Mode", modeFromBoolean(s0));
      // LED steady:  manual when s0==false -> LED ON when  manual => finalLed = !s0
      var finalLed0 = !s0;
      setManualLed(finalLed0);
      announce("Initial mode " + modeFromBoolean(s0) + " (D22=" + (s0 ? 1 : 0) + ").");
      logEvent("Initial read: D22=" + (s0 ? 1 : 0) + " => " + modeFromBoolean(s0));
    } else {
      print("Initial D22 read unstable/null.");
      logEvent("Initial D22 read unstable/null.");
    }
  }

  // Main loop
  while (true){
    try {
      var connected = EZB.isConnected(ezbIndex);

      // Handle reconnect: disconnected -> connected
      if (!wasConnected && connected){
        print("EZB reconnected - waiting " + settleOnConnectMs + "ms to settle.");
        sleep(settleOnConnectMs);
        var state = readDebouncedD22();
        if (state !== null){
          var finalLed = !state; //  manual when state==false
          if (state !== lastState){
            lastState = state;
            setVar("$Mode", modeFromBoolean(state));
            // blink then set final
            blinkManualLed(finalLed);
            announce("Mode change " + modeFromBoolean(state) + " (D22=" + (state ? 1 : 0) + ").");
            logEvent("Reconnected - Mode change detected: D22=" + (state ? 1 : 0) + " => " + modeFromBoolean(state));
          } else {
            // re-announce current mode once and ensure LED matches
            setVar("$Mode", modeFromBoolean(state));
            setManualLed(finalLed);
            announce("Mode " + modeFromBoolean(state) + " (D22=" + (state ? 1 : 0) + ").");
            logEvent("Reconnected - Mode re-announced: D22=" + (state ? 1 : 0) + " => " + modeFromBoolean(state));
          }
        } else {
          print("After reconnect: D22 unstable/null - no announcement.");
          logEvent("After reconnect: D22 unstable/null");
        }
      }

      // Normal polling while connected
      if (connected){
        var s = readDebouncedD22();
        if (s !== null && lastState === null){
          // first stable read
          lastState = s;
          setVar("$Mode", modeFromBoolean(s));
          var finalLed = !s;
          setManualLed(finalLed);
          announce("Initial mode " + modeFromBoolean(s) + " (D22=" + (s ? 1 : 0) + ").");
          logEvent("First stable read: D22=" + (s ? 1 : 0) + " => " + modeFromBoolean(s));
        } else if (s !== null && s !== lastState){
          // stable mode change
          lastState = s;
          setVar("$Mode", modeFromBoolean(s));
          var finalLed = !s;
          blinkManualLed(finalLed);
          announce("Mode change " + modeFromBoolean(s) + " (D22=" + (s ? 1 : 0) + ").");
          logEvent("Mode changed: D22=" + (s ? 1 : 0) + " => " + modeFromBoolean(s));
        }
      } else {
        // EZB not connected: nothing to do
      }

      wasConnected = connected;
    } catch(loopErr){
      print("Monitor loop exception: " + loopErr);
      logEvent("Monitor loop exception: " + loopErr);
    }
    sleep(pollMs);
  } // end main loop
}

Notes and troubleshooting

  • Log file path: default is C:\Users\Public\Documents\ModeChanges.log. If you get permission errors, change logFile to a folder you know ARC can write to (for example a folder inside your user Documents, e.g. "C:\Users\YourName\Documents\ModeChanges.log"). If the script prints "Log write error", update the path and restart the script.
  • LED polarity: script assumes D21 HIGH = LED ON. If your LED is wired active-low (i.e., port sinks to ground to turn LED ON), tell me and I’ll invert finalLed logic (use finalLed = state instead of !state).
  • Auto-start: keep a single Connection Established script line: controlCommand("EZB_D22_ConnMerge","ScriptStart") Remove any old duplicate starts for other monitor scripts.
  • If you ever manually stop the script, clear the run flag before restarting: setVar("$EZB_D22_Running","0") Then restart the Script skill.

Follow-up

  • Confirm the blink behavior looks right (double short blink). If you want faster/slower or different blink count, tell me new blinkMs or blinkCount.
  • Confirm log file is created and being appended (I can show an example format). Would you like the script to also rotate logs daily or keep multiple log files?

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.
#77  

I will have to look again to see if any log files were created, but so far in general things seem to be ok. D21 does blink as expected and is correct polarity to suite my needs at the moment (still testing...)

I need to build up the robot more, to properly test more functions of what I need , so to be continued ...

Author Avatar
PRO
Canada
#78  

Nice - glad the LED blink and polarity are working so far. Below are small, safe utilities and options you can use while you continue testing. Paste any of these into a Script skill (JavaScript tab) or the Script Console to run them.

  1. Quick checks - does the log file exist and show contents?
// Check log file existence and print the full contents
var logFile = "C:\\Users\\Public\\Documents\\ModeChanges.log";
print("Log exists: " + File.exists(logFile));
try {
  if (File.exists(logFile)) {
    var txt = File.readAllText(logFile);
    print("==== Log start ====");
    print(txt);
    print("==== Log end ====");
  } else {
    print("Log file not found at: " + logFile);
  }
} catch(e) {
  print("Error reading log: " + e);
}
  1. Clear or rotate the log manually
  • To remove the current log and start fresh:
var logFile = "C:\\Users\\Public\\Documents\\ModeChanges.log";
if (File.exists(logFile)) {
  File.delete(logFile);
  print("Deleted: " + logFile);
} else {
  print("No file to delete.");
}
  • To rename (archive) current log and create a new empty file:
var logFile = "C:\\Users\\Public\\Documents\\ModeChanges.log";
var archive = "C:\\Users\\Public\\Documents\\ModeChanges_" + (new Date()).toISOString().replace(/:/g,"-") + ".log";
if (File.exists(logFile)) {
  File.appendString(archive, ""); // create target if needed
  // No direct rename API, so copy contents then delete original:
  var contents = File.readAllText(logFile);
  File.appendStringLine(archive, contents);
  File.delete(logFile);
  print("Archived to: " + archive);
} else {
  print("No log to archive.");
}
  1. Automatic daily rotation option (drop-in helper)
  • If you want the monitor to create a new file per day, replace the single logFile variable with this function and use getLogFileForToday() when writing logs.
function getLogFileForToday() {
  var d = new Date();
  var y = d.getFullYear();
  var m = ("0" + (d.getMonth()+1)).slice(-2);
  var day = ("0" + d.getDate()).slice(-2);
  return "C:\\Users\\Public\\Documents\\ModeChanges_" + y + "-" + m + "-" + day + ".log";
}

// Example usage:
var lf = getLogFileForToday();
File.appendStringLine(lf, (new Date()).toLocaleString() + " - test entry");
print("Wrote to " + lf);
  1. Control the monitor (stop/clear run flag/start)
  • If you stop the script manually, clear the run-flag before restarting:
setVar("$EZB_D22_Running","0");
print("Cleared run flag. Now you can start the monitor safely.");
  • Start/stop the monitor skill (replace skill name if yours differs):
controlCommand("EZB_D22_ConnMerge","ScriptStop"); // stop
sleep(200);
controlCommand("EZB_D22_ConnMerge","ScriptStart"); // start
  1. Force a test mode change and immediate announce (handy while testing)
// Force-set mode and announce
var forcedMode = "Manual"; // or "Automatic"
setVar("$Mode", forcedMode);
if (EZB.isConnected(0)) Audio.sayEZB("Mode forced to " + forcedMode, 0);
else Audio.say("Mode forced to " + forcedMode);
print("Forced mode to " + forcedMode);

Notes & reminders

  • Log file path and Windows permissions: if the script prints "Log write error", change the path to a folder you know ARC can write to (e.g. a folder inside your user Documents). Default used in the monitor was C:\Users\Public\Documents\ModeChanges.log which usually is writable.
  • LED polarity: you confirmed D21 is correct for your wiring. If you later wire it active-low, I can flip the logic for you.
  • Images: I still can’t view images. If you see an error or status text in ARC, copy/paste the exact text here.
  • EZ-Script: ARC prefers JavaScript or Python. I cannot create native EZ-Script (I’ll help convert EZ-Script into JavaScript or Python if you paste it). If you want the original EZ-Script logic translated to JS, I can convert it for you.

Helpful links

Next steps - what would you like me to do?

  • Add daily file rotation into your running monitor script (I already showed the helper - I can integrate it).
  • Keep a rolling set of files (e.g., 7 days) - I can add auto-prune.
  • Convert any EZ-Script you have into JavaScript.
  • Add a visual blink pattern tweak (longer, faster, different count).

Tell me which option you want next, and whether you prefer daily logs or a single rotating file set (and the folder/path you'd like the logs placed in).


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.
Author Avatar
Unknown Country
#79  

Y999 Game in Pakistan also offers plenty of casual games in various categories of online games. These games bring the same gaming taste that you love to enjoy but this time it will involve real money earning. You can play 50+ casual games under casual game category of this real money earning app.

Author Avatar
PRO
Canada
#80  

That looks like an off-topic promotion/post (not related to ARC or EZ-B v4). Please keep the thread focused on your ARC project so we can help you effectively.

If you (or jan756434) actually have a question about Synthiam ARC, EZ-B v4, the D22/D21 monitor, or the log file behavior, please post the exact question or the exact error/status text. I can help with:

  • Verifying the ModeChanges.log file and contents (I can provide the exact check/print snippet if you want).
  • Tweaking the LED blink pattern (faster/slower/more flashes).
  • Enabling daily log rotation or a rolling set of logs.
  • Converting any EZ-Script you have into JavaScript for ARC.
  • Troubleshooting any reconnect/announce issues.

Which of those would you like me to do next? If it’s the log check, tell me the log path you used (or confirm the default C:\Users\Public\Documents\ModeChanges.log) and I’ll give the exact snippet to run.


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.