Capacitive Sensing

ytai edited this page Feb 11, 2013 · 1 revision

Capacitive Sensing

Background

Touch sensors are extremely popular these days: from touch-sensitive screens to elevator buttons. One of the most popular techniques for detecting human touch is capacitive sensing. It is based on the fact that the human body has capacitance, which can be measured and detected when it comes in contact (or even close proximity) with the touch sensitive surface. One advantage of using capacitive sensing to detect touch is that no pressure is required, only contact. Disadvantages include inability to work with gloves or any non-conductive object.

The principle of operation of capacitive sensing is very simple: when pushing electric charge Q into a capacitor, its voltage V will change in proportion to the charge. The ratio, Q/V, or "how much charge needs to be pushed in order to achieve a certain voltage change" is called capacitance and is normally designated by the letter C. Capacitance is measured in units called Farade, where one Farade is one Coulomb per Volt or one Ampere-second per Volt. Thus, in order to measure a circuit's capacitance, we can drive a known charge quantity into it (e.g. by driving known constant current for a known time period), and then observe the change in voltage.

Any conductive surface connected to a CapSense-capable pin can serve as a capacitance sensor. Aluminum foil is one of the simplest ways to create custom-shaped buttons. In some cases, the shape needs to take into account grounding, as described below.

The IOIO has 16 pins capable of capacitive sensing, which are the same pins used for analog input, namely pins 31-46 on both the IOIO V1 and the IOIO-OTG boards. All of which can be used concurrently, e.g. for connecting 16 buttons or even 64 button in an 8x8 Charlieplexing setup).

Sampling Process

Each of the 16 pins is measured once every 16ms, whereas the measurement involves charging it with 89.1uA for 1us = 89.1pC of charge, then measuring the voltage. During the rest of the time, the pin is actively pulled to ground, in order to discharge it. Thus, care must be taken not to try to impose any voltage on pins that are active in capacitive-sensing mode.

Filtering

The voltage signal is typically very noisy, and requires some filtering for good results. The CapSense module includes a built-in filter, which you can configure to be fast-and-noisy or slow-and-smooth (or any point in between). Controlling this filter is done by setting a single value, which has a time dimension. This time will tell us the typical rate of change of our filtered signal. For example, setting it to 20-50ms will give us a rather fast response, suitable for human interactions.

Grounding

Sharing a common ground between the IOIO and the person touching the sensor greatly increases the effective capacitance measured. When the IOIO is connected to earth via a wall-adapter or when connected to a desktop computer this is typically not a problem. However, in a battery-operated setup, this may result in measurements that are too small to be reliably detected. One possible solution is to design the sensor such that touching the sensor itself would also result in touching the IOIO ground, such as in the following design:

If you look closely, you will notice that there are two separate conductors on the button. One of them will be connected to ground, and the other to the CapSense pin. Their size is much smaller than a fingertip, so when touching the button both conductors will be touched.

Range and Resolution

Because of how measurement is performed, very small capacitance will cause the voltage to saturate (3.3V) during the charging, effectively limiting the minimum capacitance we can sense. Currently, this has been tuned such that this limit is about 27pF. Since the IOIO itself has some internal capacitance and some parasitic capacitance of the traces, this limit is normally only slightly higher than the no-load capacitance and is small enough to be negligible in comparison to real-life loads.

On the other hand, large capacitances would cause the voltage to change subtly as result of our constant charge. Since we are limited in our voltage sampling resolution, this effectively limits the highest possible capacitance we can measure, but even before we get there, our precision will start to deteriorate. In the current configuration, values in the order of 2700pF will have a +-10% precision (assuming no noise). Again, for the simple case of detecting human touch, this is not a problem.

Usage

Using the IOIO pins for capacitive sensing is done via the CapSense interface. An instance of this interface corresponds to one physical pin configured to operate in this mode. CapSense instances are obtained by calling one of the overloads of IOIO.openCapSense(). The simplest form is:

CapSense capSense = ioio_.openCapSense(pinNum);

This uses the default filter setting of 25ms. In order to override the filter setting, use:

CapSense capSense = ioio_.openCapSense(pinNum, filterTime);

where filterTime is in milliseconds.

Once an instance of CapSense is obtained, capacitance can be read by calling:

float picoFarade = capSense.read();

returning a value in pico-Farade units. This method might block for a few milliseconds if called immediately after the pin is open.

Most often, all we want is to detect when the capacitance has crossed some threshold, which indicates a touch. The way to do so, without constantly polling is by using the following methods:

void waitForClick() throws ConnectionLostException, InterruptedException {
  capSense.waitUnder(50);  // wait until there is no touch detected.
  capSense.waitOver(60);   // wait until touch is detected.
}

waitUnder() will block until the measured capacitance drops below 50pF; waitOver() will block until the measured capacitance rises above 60pF. The thresholds are different on purpose, in order to have some hysteresis to reduce the likelihood of a single click being detected more than once.

Last, if changing the filter time constant on-the-fly is required, one may call:

capSense.setFilterCoef(timeInMs);

which sets the characteristic time of the filter. The default of 25ms is normally suitable for detecting clicks quickly and reliably.