Thursday, June 18, 2015

Capacitive Sensing Part 2

Based on reading more about how capacitive sensing is done in touch screens, I changed to a new approach. Instead of trying to measure the time to charge or discharge the circuit, I'm relying on the fact that an RC circuit acts as a low-pass filter. Here's the circuit I'm using, essentially the same as when I was trying to time the discharge rate.

A square wave using the tone() function is applied to the input and a pin change interrupt is used to count CHANGE transitions on the output. If the tone is near the cutoff frequency, a small increase in capacitance will move the cutoff frequency lower, causing fewer output transitions.



The code looks like this (not yet made into a library), using the EnableInterrupt library to set up the pin transition interrupts.

// Start sampling
transitionCount = 0;
enableInterrupt(OUTPUT_PIN, countTransitions, CHANGE);
tone(INPUT_PIN, frequency);

delay(SAMPLE_DURATION_MS); // 50ms seems to be plenty


// Stop sampling
noInterrupts();
noTone(INPUT_PIN);
disableInterrupt(OUTPUT_PIN);
interrupts();


There is a global, volatile variable transitionCount which is incremented by the pin change interrupt handler:

void countTransitions() {
  ++transitionCount;
}

For my purposes, I'm using a threshold of 3% of the expected transitions. That is, I consider it a touch when I get 3% or less of the expected pin change transitions.

Finding the Critical Frequency

So what frequency do we send? I have found that a little under 4KHz works well, but the total capacitance is sensitive to whether the Arduino is connected to a USB cable or not. I've added code to find the right frequency at power-up using this logic:
  1. Set the frequency to 8Khz.
  2. Send the tone and count transitions. If we have 50% or more of what we expect, stop, and use that frequency for sensing.
  3. Otherwise, decrement the frequency by 100Hz and go to step 2.
Note that the expected number of transitions for a duration of n milliseconds is frequency*2*n/1000. I'm using a 50% threshold. At that frequency I can detect proximity to the touch point, too: the counts increase from zero as the human gets closer to the touch object. If you only want to detect actual touches you can use a threshold of 90% or more – the filter cutoff is pretty steep. When I get the code cleaned up I'll release it on GitHub.

Notes and Further Study

 The cutoff frequency for an RC circuit is 1/(2πRC). Since the resistance is 3MΩ, this means that for a cutoff frequency around 4KHz, the total capacitance in the circuit is only about 15pF, some of that coming from the diode. I find it somewhat remarkable that we can measure such a low capacitance with a few lines of Arduino code.

According to the Wikipedia page on Body Capacitance, a human being is roughly equivalent to a 100pF capacitor. If so, the filter cutoff frequency will be lowered to well under 1KHz when touching the sense object.

Some things to investigate further:
  • Can we drive multiple sensors from a single input line? (That's partly why I left the diode, to reduce ringing from multiple sensors.)
  • Can we sense from multiple touch points at the same time? (All outputs would be connected to ground – will they interfere with each other?)
  • Can we sense from two overlapping touch points, separated by an insulating layer? (This is one way touch-screens are made: One layer has touch points connected into rows, the other layer has columns. The intersection gives you the (x,y) position.)
  • Does this technique work when the Arduino is plugged into a wall wart? (All my testing has been under battery power – that's the configuration I want to use, but I'd like to find out how robust it is with other power sources.)
  • How much capacitance does a human add to the circuit? (Just need to find the cutoff frequency while touching the sense object.)

No comments:

Post a Comment