DIY Touch Sensor (Capacitive Sensor)

Capacitive Sensors is a technology which detects proximity or touch (by a hand/skin, or any conductive object). The sensor measures the capacitance between the input and output nodes to detect a touch. The sensor detects anything that is conductive, so these sensors can be used to replace any normal switches to make them touch sensitive or even be utilized in making touch screens for monitors, touch-pads and touch sensitive buttons in phones, laptops or other devices.  

About the Touch Sensor:
The sensor setup in the example below is a simple DIY setup without using a commercial sensor chip.

Setup:
Attach a high value resistor (1-10M Ohm) between an input and an output pin. Also connect a short bare copper or aluminum wire/foil to the input pin. If the wire is to be a longer one, make sure it isn't touching any other wires along the way, or just use a covered wire with a small uncovered area at its tip. This will be the touch sensor for the capacitive sensor (i.e. activates at touch).

An LED is also connected to a separate output pin and GND. This LED turns on when someone touches the sensor with a conductive object (e.g. capacitive sensors are most commonly used to sense touch with skin/fingers etc.)

It is also possible to vary the capacitance reading of this setup to detect even when one's hand is 3 to 4 inches from the sensor, or make it activate just on absolute touch. One can use lower values of R (e.g. 1 M Ohm or less) for absolute touch to activate the sensor. With a 10 M resistor the sensor should start to respond 1-2 inches away.

Code:
When the value at the output pin is changed from LOW to HIGH, it changes the state of input pin to LOW(or 0) for a very short time interval. This time interval is defined by:

T  =  R  x  C,

where
T  =  time interval,
R  =  resistance,
C  =  capacitance of the sensor + capacitance of any conductive object in contact with the sensor pin

So, this time interval increases if the sensor on input pin (the bare copper/aluminum wire) is touched with a conductive object. And the interval reduces again when the conductive
object is removed from the sensor.  So, we measure the length of the time interval to get a measure of capacitance on the touch sensor.

Threshold:
The value of the threshold here depends on how sensitive the user wants the sensor to be.  The lower bound of the threshold would be the value of R (the resistance) itself, since that remains constant in when measuring T = R x C. But, the upper bound can be changed depending on the requirements of the system.

Smoothing:
However, there might be a lot of jitter as well as environmental conditions that might make the
capacitance value jump around a lot. This can be overcome by using a smoothing function. For example, this can be done by reading the capacitance measure for a number of times and then averaging the values overall.

Circuit:

Schematic:
Sample Arduino Program:
About this Code:
When the output at pin4 transitions from LOW to HIGH, it changes the state of input pin5 to LOW(or 0) for a very short time interval. This time interval increases if the sensor on input pin5 is touched with a conductive object and vice versa.

At the start of each main loop cycle in this program, we set the value of a variable 'capX' to 0. Then for the time interval the value at input pin5 returns LOW, we increment 'capX'. This results in 'capX' being barely incremented if the sensor is not in contact with a conductive object. But, as soon as someone holds/touches the sensor the value of capX quickly increments because of the longer time interval. So, if the capX value is bigger than a given threshold, it means the sensor just detected a touch.

The value of the threshold here depends on how sensitive the user wants the sensor to be and/or the environmental affect the initial value at the sensor itself.

/*

This code turns the LED on while the sensor is in contact
with a conductive material (e.g. when someone touches it
with their bare skin/fingers)

Setup:
Attach a high value resistor (1-10M Ohm) between an output
pin 4 and input pin 5. Also connect a short bare copper or
aluminum wire/foil to the input pin5. Connect an LED to
output pin13 and GND.

By: Naureen Mahmood.

*/

#define LED        13
#define THRESHOLD   5

int capI;      // interval when sensor pin 5 returns LOW

void setup()
{
  Serial.begin(9600);
  pinMode(LED, OUTPUT);
  pinMode(4, OUTPUT);     // output pin
  pinMode(5, INPUT);      // input pin
}

void loop()
{
  capI = 0;      // clear out capacitance measure at each loop

  // transition output pin4 LOW-to-HIGH  to 'activate' sensor pin5
  digitalWrite(4, HIGH);     

  // On activation, value of pin 5 stays LOW for a time interval T = R*C.
  // C is big if the sensor is touched with a conductive object.
  // Increment capI for the interval while pin5 is LOW
  int val = digitalRead(5);  // read the input to be checked
  while (val != HIGH){   
    capI++;   
    val = digitalRead(5);    // re-read the input to be checked
  }
  delay(1);
 
  // transition output pin4 HIGH-to-LOW to 'deactivate' sensor pin5
  digitalWrite(4, LOW);     
  Serial.println(capI, DEC);  // print out interval

  if (capI > THRESHOLD)       // Turn LED on if capI is above threshold
    digitalWrite(LED, HIGH);
  else 
    digitalWrite(LED,  LOW);
}


Sample Arduino Code (with smoothing filter):

About this Code:
 This code uses the same technique for measuring capacitance as  the earlier one. But, this one also uses a smoothing filter to  remove any jitter along the measured values by averaging 4 consecutive values from the input pin. Then at each iteration of that 4-time loop, after transitioning the output pin 4 from low to hi, we measure the duration for which the value at input pin 5 remains low (and save it in variable capLo). Then we transition the output pin 4 back to low, and measure the duration for which the input pin 5 is high (and save it in variable capHi). We won't be using the capHi variable for the filter but, this helps read out any noise at the input pin before the next iteration.

After this loop, the smoothing filter is applied to the measured capLo value. We use the current capLo value and previous filtered value, called prevCapI, from the last iteration of the loop function (not the for-loop), and multiply them by f_val and (1 - f_val) respectively. Here f_val is the amount of filtering to be applied to the measured capacitance values. This value can be between 1 (no filter) and 0.001 (max filter). This makes sure both the current and previous values of the measured capacitance are included in the final filtered value, and the value f_val determines what proportion of each is to be included in the final value. Therefore, even the sudden changes in the capacitance are smoothed out based on previous input.

So, then the LED brightens or dims smoothly based on these filtered values from the touch sensor.

/*    

 This code makes the LED intensity go from dim to bright
 smoothly when someone touches the sensor with a bare
 finger, and then smoothly dims down to turn off after
 the person lets go of the sensor.

 Setup:
 Attach a high value resistor (1-10M Ohm) between output
 pin 4 and input pin 5. Also connect a short bare copper or
 aluminum wire/foil to the input pin5. Connect an LED to
 output pin 11 (or any PWM pin) and GND.

 [ Smoothing filter based on code by Paul Badger found at:
   http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1171076259 ]

 By: Naureen Mahmood
 */

// You can change the bounding values for the capacitive/touch
// sensor depending on what values work best for your setup
// + environmental factors
#define LOW_T       10    // lower bound for touch sensor
#define HIGH_T      60    // upper bound for touch sensor
#define LED         11    // LED output pin

// These are variables for the low-pass (smoothing) filter.
float prev_capI;    // previous capacitance interval
float filt_capI;    // filtered capacitance interval
float f_val = .07;  // 1 = no filter, 0.001 = max filter
unsigned int capLo; // duration when sensor reads LOW
unsigned int capHi; // duration when sensor reads HIGH

void setup()
{
  Serial.begin(9600);

  pinMode(LED, OUTPUT);
  pinMode(4, OUTPUT);    // output pin
  pinMode(5, INPUT);     // input pin
}

void loop()
{  
  // clear out the capacitance time interval measures at start
  // of each loop iteration
  capHi = 0;
  capLo = 0;

  // average over 4 times to remove jitter
  for (int i=0; i < 4 ; i++ )
  {      
    // LOW-to-HIGH transition
    digitalWrite(4, HIGH);   

    // measure duration while the sense pin is not high
    while (digitalRead(5) != 1)
      capLo++;
    delay(1);

    //  HIGH-to-LOW transition
    digitalWrite(4, LOW);             

    // measure duration while the sense pin is high
    while(digitalRead(5) != 0 )    
     capHi++; 
    delay(1);
  }

  // Easy smoothing filter "f_val" determines amount of new data
  // in filt_capI
  filt_capI = (f_val * (float)capLo) + ((1-f_val) * prev_capI);   
  prev_capI = filt_capI; 

  Serial.println( filt_capI ); // Smoothed Low to High

  // Map the capacitance value range to LED brightness (0-255)
  int ledVal = map (filt_capI, LOW_T, HIGH_T, 0, 255);

  if (filt_capI > LOW_T)
    analogWrite(LED, ledVal);
  else
    analogWrite(LED, 0);
}

1 comment:

  1. This was extremely helpful! Your explanations really helped me to understand capacitive sensing, and I was able to make my own paper keyboard using capacitive sensing after reading this.

    ReplyDelete