1
\$\begingroup\$

I am trying to implement touch functionality of esp32 development board to toggle a led. But on uploading a simple touch detection sketch, output have spikes i.e. usually value remains near 100 but falls to around 30 randomly for no reason. This triggers false touch. I have tried this with two esp32 dev boards I have and the problem persists in both. Also I have tried this with and without external wire from the touch pin.

Code I've used:-

void setup() {
  Serial.begin(115200);
}

void loop() {
  Serial.println(touchRead(27));
  delay(10);
}

Serial plotter output:-

  1. Without external wire connected with touch pin Without external wire connected with touch pin

  2. With external wire connected with touch pin With external wire connected with touch pin

UPDATE:- 3. Actual touch represented by T1, T2, T3 Actual touch

\$\endgroup\$
7
  • \$\begingroup\$ It's hard to know what is going on here as 99% of the functionality is not in your code but hiding behind the scenes. But with an apparent cycle time of 100 readings per second, a single-sample glitch cannot reasonably be a touch, and should probably be ignored. Eg, don't act unless you see several readings over a short period of time. Something purporting to be a simple to use touch detection would seemingly already need to do that, but perhaps tuning the time filtering is too need dependent to hide it in the arduino method body, or perhaps the built in filtering is just not good. \$\endgroup\$ Commented Oct 4, 2020 at 11:54
  • \$\begingroup\$ That doesn't mean there aren't inappropriate sources of electrical noise in your setup, but it's quite possible to write software rules which "look" at your plots and say "nope, that doesn't look like a touch". Doing so is perhaps a bit beyond the scope of an SE answer, but editing your question to include a plot of an actual touch would be an illustrative comparison. \$\endgroup\$ Commented Oct 4, 2020 at 11:57
  • \$\begingroup\$ Thanks chris-stratton for your interest. I've updated the question with actual touch graph. Actually I had tried filtering false touch by calcualting timings of actual touch but I think that actual touch is very much similar to false one hence sometimes false touch is also considered as actual touch. Anyway please let me know if false touch can be filtered. \$\endgroup\$
    – Rishabh
    Commented Oct 4, 2020 at 12:18
  • 1
    \$\begingroup\$ Fatter pulses = touch. Start from there. \$\endgroup\$
    – Andy aka
    Commented Oct 4, 2020 at 13:09
  • \$\begingroup\$ please share circuit diagram \$\endgroup\$
    – Deepak
    Commented Oct 4, 2020 at 13:12

4 Answers 4

2
\$\begingroup\$

This might be a little late, but I ran into the same thing and wrote some code to 'de-glitch' the signals: https://github.com/digamesystems/CapacitiveTouchTest

The gist is to use a little 3 point 'history' of readings to look for single point 'glitches' and then remove them.

Filtering and baseline subtraction also helps:

/*****************************************************************************
 CapacitiveTouchTest: Playing with the capacitive touch inputs on the ESP32
 
 Based on the Espressif ESP32 TouchRead example code. Adding in de-glitching 
 and smoothing of the reported values and dynamic baseling tracking.
 Touch0 is T0 which is on GPIO 4.
 J. Price, 2022. -- Based on the Espressif ESP32 TouchRead example code.
 The touchRead function in the ESP Arduino API seems to be susceptible to 
 noise. A number of people have reported 'glitching' in the signal. (Sharp,
 single-point spikes in the data.) This code adds a simple de-glitching 
 feature and provides the option to smooth the data to reduce noise. 
 Feel free to play with the smoothing constants to fit your application. 
 
*****************************************************************************/

float p1=0.0, p2=0.0, p3=0.0;  // 3-Point history
float raw = 0.0; // Current reading
float baseline = 0.0;
float smoothed = 0.0;
unsigned long count=0; 

// Smoothing factors. The closer to one (1.0) the smoother the data. Smoothing 
// introduces a delay. 
const float dataSmoothingFactor = 0.95;       
const float baselineSmoothingFactor = 0.9995;


/*****************************************************************************/
void setup()
{
  Serial.begin(115200);
  delay(1000); // give me time to bring up serial monitor
  Serial.println("Smoothed Raw De-Glitched");

  // Intialize history and smoothed value to an average of a few readings
  for (int i = 0; i<100; i++){
    raw += touchRead(T0);
    delay(10);
  }
  raw = raw /100;
  p3 = raw;
  p2 = raw;
  p1 = raw;
  smoothed = raw;
  baseline = raw;
}


/*****************************************************************************/
void loop()
{
  // Current value
  raw = touchRead(T0);
  
  p1 = raw; // Latest point in the history
  
  // Glitch detector
  if (abs(p3-p1) < 5) {   // The latest point and the two points back are pretty close 
    if (abs(p2-p3) > 3) { // The point in the middle is too different from the adjacent points -- ignore
      p2 = p3;
    }
  }

  // Smooth the de-glitched data to take out some noise
  smoothed = p3 * (1 - dataSmoothingFactor) + smoothed * dataSmoothingFactor;

  // Dynamic baseline tracking -- a much longer view of the de-glitched data
  if ( count > 50 ){ 
   baseline = p3 * (1 - baselineSmoothingFactor) + baseline * baselineSmoothingFactor;
  }

  // Shift the history
  p3 = p2;
  p2 = p1;
  
  Serial.println( String(smoothed - baseline) + "," + String(raw - baseline + 20) + "," + String(p3 - baseline + 10) );  // get value using T0

  delay(30);
}
\$\endgroup\$
0
1
\$\begingroup\$

On studying graph, it is observed that actual touch lasts around 80 to 100 ms and false touch lasts for much less time. Although I had tried some filters before but turns out that was just too complicated, a simple filter works fine (my siliness).

Working code:-

boolean touchStarted = false;
unsigned long touchTime = 0;
int threshold = 90;
int touchMinDuration = 100;

void setup() {
  Serial.begin(115200);
}

void loop() {
  int t = touchRead(27);
  if (t < threshold && !touchStarted) { // on fresh touch
    touchStarted = true;
    touchTime = millis();
  } else if (t >= threshold && touchStarted) { // untouched
    if (millis() - touchTime > touchMinDuration)
      touched;
    touchStarted = false;
  }
  delay(10);
}

void touched(){
  Serial.println("Touched");
}

Thanks to the comments which helped me to come on this solution.

\$\endgroup\$
1
\$\begingroup\$

Just started playing with the touch sensor on ESP32 and Arduino myself and saw your post. I also see unstable readings occasionally. It seems to work much better if I do a dummy read then delay 10 microseconds and then read the real touch value. I have not played much with altering the delay between reads.

Not sure what is going on but it seems to work well with the pre-read dummy read. Extra filtering and a time duration is probably a good idea to add for touch sensing also.

uiTouchByte = touchRead(TOUCH_PIN);  // EXTRA READ IS NECESSARY?
delayMicroseconds(10);

uiTouchByte = touchRead(TOUCH_PIN);  // run the sampling of touch
\$\endgroup\$
1
\$\begingroup\$

Simplest work around false positive touchRead.
Tried and tested, no repeat trigger, regardless how long you hold the touchpad.

BTW: T6=GPIO14.

void setup()
{
    Serial.begin(115200);
}

void loop()
{
    if (touchRead(T6) < 40)
    {
        delay(100);
        
        if (touchRead(T6) < 40)
        {
            delay(100);             
            
            if (touchRead(T6) < 40)
            {
                touched();
                
                while (touchRead(T6) < 40) {}
            }
        }
    }
}

void touched()
{
    Serial.println("Touched");
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.