Slide Script icon Slide Script — Adjust a numeric variable via slider (0-1000) with customizable min/max, center button and scripts triggered on value change or bonus button press. Try it →
Asked
1 Participant
Sharp IR on ESP32 noisy readings

Sharp IR On ESP32 Noisy Readings

I’m trying to use a Sharp GP2Y0A21YK IR sensor on an ESP32 DevKitC (WiFi) to stop my little 2WD rover before it kisses a wall. In ARC I’m connected to the ESP32 via the EZB Connections skill as Board #5, and I’ve added the Sharp IR Collision skill pointing at ADC0 on that board. Sensor is powered from a 5V buck (common ground), and the analog output goes through a divider (20k/10k) into the ESP32 ADC since it’s 3.3V max. Multimeter shows about 1.1-1.3V at ~20-25 cm and it tracks nicely when I move a target in/out.

In ARC though, the Sharp IR Collision value and voltage bounce around when the motors run, causing random stops. Things I’ve tried: 0.1 F cap from VO to GND, tried 1k series + 0.1 F RC low-pass, moved grounds to a star point, 220 F on the 5V buck, separate 5V regulator for the sensor, different ADC pin, and even a different ESP32. Using a JavaScript loop with GetADC(5, ADC0) and averaging 10-20 samples looks much more stable, but the Sharp IR Collision skill still reacts to the raw read since I can’t feed it my filtered value. Also, the skill UI shows 0-5V, which makes me wonder if it assumes a 5V ADC reference and throws off scaling for 3.3V boards.

Two questions rolled into one: is there a way to add smoothing or adjust ADC scaling for the Sharp IR Collision skill when using an ESP32, or should I bypass the skill and handle stop/resume in a script, and if scripting is the way, what’s the cleanest way to pause and then resume a Movement Panel from JavaScript based on an averaged GetADC threshold?



Related Hardware (view all EZB hardware)
Esp32 by Espressif
Flash Synthiam ESP32 firmware to create a Wi-Fi EZB robot controller with ARCx for servos, sensors, scripting and web control
Wi-Fi
Servos Varies
Camera
Audio
UART Varies
I2C
ADC Varies
Digital Varies

Related Robot Skills (view all robot skills)
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
Displays HC-SR04 ultrasonic distance readings in ARC; scriptable via GetPing(), pausable, sets a variable with multiplier, optional NMS output

ARC Pro

Upgrade to ARC Pro

ARC Pro will give you immediate updates and new features needed to unleash your robot's potential!

Author Avatar
PRO
Canada
Twitter YouTube GitHub
#1  

Yes - for this setup, the proven better approach is to bypass the Sharp IR Collision skill and handle the sensor in a Script skill with filtered ADC readings.

Why I recommend scripting instead of Sharp IR Collision

The Sharp IR Collision skill is a simple stop trigger. It’s useful on straightforward analog sensors, but it does not let you:

  • apply custom smoothing
  • debounce noisy readings
  • tune hysteresis for stop/resume
  • compensate for ESP32-specific ADC behavior

And you’re right to question the display: the skill was designed around a generic ADC workflow and is not a good fit when an ESP32 analog input is being used with motor noise. On ESP32, the ADC is also known to be more sensitive than many users expect, especially with brushed motor noise nearby.

So the clean solution is:

  1. Read ADC.get(ADC0, 5) on the ESP32
  2. Average multiple samples
  3. Use a stop threshold and a separate resume threshold
  4. Send Movement.stop() or Movement.forward() as needed

That gives you control over the behavior instead of fighting the built-in skill.


Use two thresholds:

  • Stop threshold: if averaged value goes below this, stop
  • Resume threshold: if averaged value rises above this, allow motion again

This prevents oscillation around the cutoff point.

JavaScript example

Add a Script robot skill and use this:

var stopThreshold = 120;
var resumeThreshold = 135;
var samples = 15;
var intervalMs = 20;

var obstacleDetected = false;

function readAveragedAdc() {
  var total = 0;

  for (var i = 0; i < samples; i++) {
    total += ADC.get(ADC0, 5);
    sleep(intervalMs);
  }

  return total / samples;
}

while (true) {
  var value = readAveragedAdc();
  print("Filtered ADC0: " + value);

  if (!obstacleDetected && value < stopThreshold) {
    obstacleDetected = true;
    Movement.stop();
    print("Obstacle detected - stopping");
  }
  else if (obstacleDetected && value > resumeThreshold) {
    obstacleDetected = false;
    print("Obstacle cleared - resume allowed");
    // Only resume if something else is supposed to be driving forward
    // Movement.forward();
  }

  sleep(50);
}

Important note about resume behavior

I want to be direct here: you usually should not automatically call Movement.forward() after a stop unless your robot is already in a "go forward" mode.

A stop skill is only one piece of behavior. Better architecture is:

  • your driving logic decides when to move
  • the IR monitor decides when to allow or block movement

If you want the rover to keep driving until blocked, then yes, your script can reissue Movement.forward(). But if your robot has manual driving or a navigation skill, the stop monitor should only stop motion and then clear the condition when safe.


If you want it as a pause/resume gate

If your goal is "stop movement when too close, then let normal movement continue when clear," use a boolean flag like this:

var stopThreshold = 120;
var resumeThreshold = 135;
var samples = 15;
var obstacleDetected = false;

function readAveragedAdc() {
  var total = 0;
  for (var i = 0; i < samples; i++) {
    total += ADC.get(ADC0, 5);
    sleep(20);
  }
  return total / samples;
}

while (true) {
  var value = readAveragedAdc();

  if (!obstacleDetected && value < stopThreshold) {
    obstacleDetected = true;
    Movement.stop();
    print("Stopped");
  }

  if (obstacleDetected && value > resumeThreshold) {
    obstacleDetected = false;
    print("Clear");
  }

  sleep(50);
}

Then your separate control logic can decide when to call Movement.forward() again.


If you want the motor noise issue to be even cleaner

Since you already tried the obvious analog filtering, here are the next best ARC-side improvements:

  • Use averaging with hysteresis as above
  • Increase sample count if response speed allows it
  • Read less often, not faster
  • Keep motor power and sensor power wiring physically separated
  • Make sure the ESP32 ground and motor driver ground meet at a single solid point
  • Avoid ADC pins that share noisy board traces if possible

But the main issue is not wiring anymore - it’s that the built-in collision skill is too rigid for a noisy environment.


About the ADC scaling concern

You’re right that the UI showing 0-5V is not ideal for an ESP32 input chain. The actual sensor and divider relationship matters more than the UI label.

For practical obstacle stopping, don’t think in volts first - think in the raw ADC values you observe in ARC and set your thresholds from real tests. That is much more reliable than assuming perfect voltage scaling.


Best practice in ARC

If this is part of a bigger rover behavior, the better ARC design is:

  • Movement Panel for driving
  • Script for sensor logic
  • optionally a custom robot skill if you want a reusable polished solution

If you want, you can even turn this into a custom robot skill later using Synthiam’s robot skill framework: https://synthiam.com/Support/Create-Robot-Skill/Overview


What I’d do in your project

I would:

  1. Remove Sharp IR Collision
  2. Add a Script skill
  3. Average the ESP32 ADC reads
  4. Add hysteresis
  5. Use Movement.stop() on obstacle detect
  6. Let your driving logic re-enable motion when clear

That will be far more reliable than trying to make Sharp IR Collision do something it wasn’t designed for.


One question so I can give you the exact script

What is the bigger behavior you want the rover to do?

  • manual drive with emergency stop
  • autonomous forward drive with stop/resume
  • wall-following / obstacle avoidance
  • navigation with a Movement Panel

If you tell me that, I can give you the cleanest ARC JavaScript pattern for your exact goal.

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

The averaging caused too much delay. I also noticed that some of my scripts didn't reference the board index. I moved my EZB to board #0, and it seems to be performing better now. It must have been a combination of a few things.

Author Avatar
PRO
Canada
Twitter YouTube GitHub
#3  

That makes sense - and moving the EZB to Board #0 often removes a lot of confusion in ARC, especially when scripts or robot skills are assuming the default board.

A few things were likely happening together:

  • Board index mismatch in scripts or robot skills
  • Noise from the motor system affecting the analog reading
  • Averaging latency making the stop response feel sluggish

For something like a Sharp IR stop sensor, a small filter + hysteresis is usually better than heavy averaging. For example, 3-5 samples is often enough, or even a simple median of 3 if you want faster reaction.

If you want, I can give you a low-latency JavaScript version for ARC that:

  • reads Board #0 explicitly
  • uses a fast filter
  • stops on a threshold
  • resumes with hysteresis

That would be a better long-term pattern than relying on the Sharp IR Collision skill for a noisy setup.

If you’d like, I can also help you convert your current script into a cleaner ARC JavaScript version.

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.