Asked — Edited

IR Sensor Reading Optimization

Hello @Athena,

I would appreciate your review of the following JavaScript code within the ARC environment. The script is designed to process infrared (IR) sensor readings, which can vary significantly due to sensor noise. My objective is to obtain a reliable result, finalLowIR, that only changes when the last three samples are consistent.

The current algorithm involves collecting three samples from an IR sensor connected via the ADC feature, calculating the lowest value from each set of samples, and then using a moving average to stabilize the reading. The final variable finalLowIR is adjusted to limit variability.

//$IRSAMPLE consists of three sample IR readings.
//lowIR is identified as the lowest of the three $IRSAMPLE readings.
//totLowIR aggregates the sum of three lowIR readings.
//avgLowIR is calculated as ((totLowIR * 1000)/3).
//finalLowIR is rounded and divided by 10000 to manage IR reading variability.

while(true) {
    var totLowIR = 0;
    var avgLowIR = 0;

    for(var count1 = 0; count1 < 3; count1++) { // Loop for 3 samples
        var lowIR = 300;
        
        for (var count = 0; count < 3; count++) { // Capture individual samples
            setVar("$IRSAMPLE", ADC.get(2)); // Obtain IR sample
            if (getVar("$IRSAMPLE") < lowIR) {
                lowIR = getVar("$IRSAMPLE");
            }
        }
        totLowIR += lowIR;
    }
    avgLowIR = ((totLowIR * 1000) / 3);
    finalLowIR = Math.round(avgLowIR / 10000);
    
    setVar("$IRADC", finalLowIR); // Store the final reading
    sleep(100); // Pause the loop for 100ms
}

Could you provide feedback or suggestions for a more efficient script in this context? Your expertise would be greatly appreciated.

Thank you,
Jack



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)
ADC Graph by Synthiam
Historical ADC graph and numeric readout (0-255) for 0-3.3/5V inputs; configurable board/port, sample interval, color, and pause for ezb controllers.
ADC Value by Synthiam
Display ADC port voltage and 0-255 linear values (0-3.3/5V); configurable board/port, units, multiplier and sample interval.

ARC Pro

Upgrade to ARC Pro

Unleash your creativity with the power of easy robot programming using Synthiam ARC Pro

Author Avatar
PRO
Canada
Twitter YouTube GitHub
#1  

Thanks - nice explanation of your intent. Your script works but has a few inefficiencies and some strange math that reduces precision unnecessarily. Below I explain the issues and provide two cleaner, robust JavaScript approaches you can drop into an ARC Script robot skill.

Key notes up front

  • Use ADC port constants (ADC0..ADC7) instead of numeric literals (per ARC notes): ADC.get(ADC2) rather than ADC.get(2).
  • ADC.get() returns 0-255 (use ADC.get12Bit() if you need finer resolution).
  • Avoid setVar/getVar in the inner sampling loop - read ADC.get() directly, and only setVar() when you want to publish the stable result.
  • Your current math reduces the result by a factor of 10 (totLowIR/30 -> average/10). That loses resolution and makes results weird. I assume you intended smoothing, but use explicit smoothing or stability checks instead.
  • For IR noise, median-of-samples + a 3-sample stability (or tolerance-based equality) is a good approach. Alternatively, an exponential moving average (EMA) provides smooth responsiveness.

Option A - Median sampling + 3-sample stability (recommended) Behavior: for each cycle, take several quick ADC samples, compute a robust sample (median). Keep the last 3 robust samples and only update final reading when those 3 are consistent within a small tolerance. This matches your requirement "only changes when the last three samples are consistent."

// Median + 3-sample stability
function median(arr){
  arr = arr.slice().sort(function(a,b){return a-b;});
  return arr[Math.floor(arr.length/2)];
}

const ADC_PORT = ADC2;         // ADC0..ADC7 - change if needed
const samplesPerCycle = 5;     // number of quick samples per cycle
const sampleDelayMs = 20;      // delay between quick samples (ms)
const loopDelayMs = 100;       // main loop delay (ms)
const stabilityTolerance = 2;  // allowed variation between last 3 readings

let lastThree = [];
let finalLowIR = null;

while(true){
  // gather quick samples and take median to remove spikes
  let quick = [];
  for(let i=0;i<samplesPerCycle;i++){
    quick.push( ADC.get(ADC_PORT) );
    sleep(sampleDelayMs);
  }
  let robustSample = median(quick);

  // save last 3 robust samples
  lastThree.push(robustSample);
  if(lastThree.length > 3) lastThree.shift();

  // if we have 3, check for stability
  if(lastThree.length === 3){
    let mx = Math.max(lastThree[0], lastThree[1], lastThree[2]);
    let mn = Math.min(lastThree[0], lastThree[1], lastThree[2]);

    if((mx - mn) <= stabilityTolerance){
      // stable -> publish averaged stable value
      let newVal = Math.round((lastThree[0] + lastThree[1] + lastThree[2]) / 3);
      if(finalLowIR === null || newVal !== finalLowIR){
        finalLowIR = newVal;
        setVar("$IRADC", finalLowIR); // publish stable IR value
        print("IR updated: " + finalLowIR);
      }
    }
    // otherwise ignore (not stable)
  }
  sleep(loopDelayMs);
}

Why this is good:

  • Median per-cycle reduces single-sample spikes.
  • Stability is explicit: only updates when three consecutive robust samples are within tolerance.
  • You keep full ADC resolution (0-255) and only average/round at the point you publish.

Tuning:

  • samplesPerCycle: increase for more robust median, but slower response.
  • sampleDelayMs: fast sensors can use 10-30ms.
  • loopDelayMs: determines how often you attempt to update final value.
  • stabilityTolerance: if sensor jitter is larger, increase tolerance (e.g., 3-6). If very strict, set 0 or 1.

Option B - Exponential Moving Average (EMA) + threshold (more responsive) Behavior: smooths the value continuously; update final only when smoothed value changes by a meaningful threshold (debounce).

// EMA smoothing + threshold
const ADC_PORT = ADC2;
const sampleDelayMs = 50;
const loopDelayMs = 100;
const alpha = 0.2;           // 0 < alpha <= 1 (higher alpha -> faster response)
const publishThreshold = 2;  // only publish if smoothed value changes by at least this

let ema = ADC.get(ADC_PORT); // initialize EMA to first reading
setVar("$IRADC", Math.round(ema));
print("IR initial: " + Math.round(ema));

while(true){
  // single sample per loop (you can replace with median of quick samples if desired)
  let r = ADC.get(ADC_PORT);
  ema = (alpha * r) + (1 - alpha) * ema;

  let rounded = Math.round(ema);
  if(Math.abs(rounded - getVar("$IRADC", -9999)) >= publishThreshold){
    setVar("$IRADC", rounded);
    print("IR updated EMA: " + rounded);
  }

  sleep(loopDelayMs);
}

Why this is good:

  • EMA is computationally cheap and smooths noise while remaining responsive.
  • publishThreshold prevents tiny fluctuations from triggering changes.

Extra tips & links

  • If you need higher resolution, try ADC.get12Bit(ADC2) (returns 0-4095) and adapt the smoothing/tolerances.
  • Display live values with the ADC Graph or ADC Value skills while tuning:
  • Use print() for debugging inside ARC scripts (preferred to console.log()).
  • If you want to base logic on "closest reading" (min) instead of median, you can replace median() with Math.min(...quick), but min is susceptible to spikes - median is safer.

Questions so I can make this even more specific

  1. Which ADC port are you using? (Use ADC0..ADC7 constant - e.g., ADC2)
  2. Do you prefer absolute stability (no publish until all 3 identical) or "stable within N" tolerance?
  3. Do you want faster updates or maximum stability? (I can tune alpha, sample counts, tolerances accordingly.)
  4. Are you using ADC.get (8-bit) or would you like to switch to ADC.get12Bit for better resolution?

If you tell me your port and the acceptable tolerance & update rate, I’ll adapt the code to those exact numbers and give recommended values for sample counts/delays.


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.