What You Should Know about Arduino Sensors: Using Capacitive Sensors - dummies

What You Should Know about Arduino Sensors: Using Capacitive Sensors

By John Nussey

You can make use of capacitive sensors in your Arduino project. Capacitive sensors detect changes in electromagnetic fields. Every living thing — even you — has an electromagnetic field. Capacitive sensors are extremely useful because they can detect human contact and ignore other environmental factors. You’re probably familiar with high-end capacitive sensors because they are present in nearly all smartphones, but they have been around since the late 1920s. You can find Arduino kits with capacitive sensors that you can hook up easily, such as capacitive touch keypads. But it’s just as easy to make your own capacitive sensors with an Arduino and an antenna.

Consider the following when you are planning a sensor for your Arduino project:

  • Complexity: Because all that is required is an antenna, you can be creative with what the antenna is and where it is placed. Short pieces of wire or copper tape are great for simple touch sensors. The piece of copper tape suddenly becomes a touch switch, meaning that you don’t even need a pushbutton to get the same functionality. You could even connect the antenna to a bigger metal object such as a lamp, turning it into a touch lamp.

If the antenna is made from a reel of wire or a piece of foil, you can extend the range of the sensor beyond touch, which is known as a projected capacitive sensor. Using a capacitive sensor you can detect a person’s hand a few inches away from the antenna, which creates a lot of new possibilities for hiding sensors behind other materials. These discreet capacitive sensors are now commonly seen in many recent consumer electronics to remove physical buttons and maintain the sleek shape of the product. The electronics can also be placed under layers of other material, protected from the outside world.

Capacitive touch sensors are easy to make. The difficulty with projected field sensors to determine the range of the field. The best way to determine this range is by experimentation, testing to see whether the field that you’re generating is far-reaching enough.

  • Cost: A capacitive touch kit designed for a specific purpose costs around $15 to $25. The kit should perform its job well, but it will be limited to the design of the interface. A capacitive sensor breakout board from SparkFun for around $10 lets you control up to 12 capacitive sensors. You have to wire your own touchpads, but you’re free to design an interface that suits your purpose.

The cheapest option is to use the CapSense library for Arduino, which allows you to make a capacitive sensor with an antenna and no additional hardware! You can spend a few cents for an antenna or repurpose an old one.

  • Location: Capacitive touch sensors can work with any conductive metal, so if you can design an attractive metal exterior, the only work will be to connect that exterior to your Arduino. If you’re looking for something more discreet, you may want to experiment with different layers of wood or plastic to hide your metal antenna. A thin layer of plywood allows the metal to be close to the surface, able to trigger the sensor. By covering the antenna with a non-conductive surface, you also give it a seemingly magical property, ensuring that people are left guessing at how it works.

The easiest way to make a capacitive sensor is to use the CapSense library by Paul Badger. By using the CapSense library, you can replace the mechanical switches with highly robust capacitive touch sensors or capacitive presence detectors.

Getting the CapSense Arduino library

The CapSense library is available from GitHub, an online repository of software that manages different versions and allows you to see who has updated the software, and how. It’s an excellent system for sharing and collaborating on code projects. You can find the Arduino platform on GitHub; check it out if you’re curious about any changes. To get the library:

  1. Point your web browser to the GitHub CapSense page.
  2. On the CapSense page, click the Clone button or download and then click Download ZIP.

    The latest version of the library is downloaded to your downloads folder or a folder you specify.

  3. Rename the folder CapSense.

    Inside the folder, you should see a number of files ending in .h and .cpp as well as an Examples folder.

  4. Move the entire folder to your Arduino libraries directory.

    This directory should be the same as the one that your sketches are saved to, for example: Username/Documents/Arduino/libraries. If you don’t have a libraries directory, create one.

    Your can find your Arduino Save directory by choosing Arduino →   Preferences from the Arduino menu bar. After the CapSense library is inside this folder, it will be available the next time you run Arduino.

  5. Start or restart Arduino and go to Sketch →   Include Library in the Arduino menu.
    Look for CapSense under the Contributed libraries section. If you don’t find it, check your directories and spelling and then restart Arduino.

Implementing the CapPinSketch sketch

For this project, you need the following:

  • An Arduino Uno
  • A wire antenna
  • Crocodile clips (optional)

As you can see below, little work is needed. You can simply have a wire antenna connected to pin 5, and you can enlarge your antenna by connecting it to any other conductive surface. Crocodile clips are useful to latch onto different antennas quickly and easily.

DIY capacitive sensor Arduino
A photo of a DIY capacitive sensor.

Build the CapSense circuit, and choose File →   Examples →   CapSense →   Examples →   CapPinSketch from the Arduino menu to load the sketch.

#include 

/* CapPin
 * Capacitive Library CapPin Demo Sketch
 * Paul Badger 2011
 * This class uses the built-in pullup resistors read the capacitance
 * on a pin.
 * The pin is set to input and then the pullup is set,
 * A loop times how long the pin takes to go HIGH.
 * The readPin method is fast and can be read 1000 times in under 10 mS.
 * By reading the pin repeated you can sense "hand pressure"
 * at close range with a small sensor. A larger sensor (piece of foil/metal)
 * will yield
 * larger return values and be able to sense at more distance. For
 * a more sensitive method of sensing pins see CapTouch
 * Hook up a wire with or without a piece of foil attached to the pin.
 * I suggest covering the sensor with mylar, packing tape, paper or other
 * insulator to avoid having users directly touch the pin.
 */

CapPin cPin_5 = CapPin(5);  // read pin 5

float smoothed;

void setup() {

 Serial.begin(115200);
 Serial.println("start");
 // slider_2_7.calibrateSlider();

}

void loop() {

 delay(1);
 long total1 = 0;
 long start = millis();
 long total = cPin_5.readPin(2000);

 // simple lowpass filter to take out some of the jitter
 // change parameter (0 is min, .99 is max) or eliminate to suit
 smoothed = smooth(total, .8, smoothed);

Serial.print( millis() - start);   // time to execute in mS
Serial.print("\t");
Serial.print(total);         // raw total
Serial.print("\t");
Serial.println((int) smoothed);    // smoothed
delay(5);
}

// simple lowpass filter
// requires recycling the output in the "smoothedVal" param
int smooth(int data, float filterVal, float smoothedVal){

 if (filterVal > 1){   // check to make sure param's are within range
  filterVal = .999999;
 }
 else if (filterVal <= 0){
  filterVal = 0;
 }

 smoothedVal = (data * (1 - filterVal)) + (smoothedVal * filterVal);

 return (int)smoothedVal;
}

Press the Compile button to check your code. Compiling highlights any grammatical errors, which light up in red. If the sketch compiles correctly, click Upload to send the sketch to your board. When it has finished uploading, open the serial monitor, set the baud rate to 115200, and touch or approach the antenna. You should see two values racing down the screen. On the left is the raw value being read; on the right is the same reading after smoothing.

If nothing happens, double-check your wiring:

  • Make sure that you’re using the correct pin number.
  • Check the connections on the breadboard. If the jump wires or components are not connected using the correct rows in the breadboard, they will not work.

Understanding the CapPinSketch Arduino sketch

At the start of the CapPinSketch sketch in the declarations, a new CapPin object is named. Note that cPin_5 is the name and it is assigned to pin 5 using CapPin(5):

CapPin cPin_5 = CapPin(5); // read pin 5

A float named smoothed is declared to store the processed value of the sensor:

float smoothed;

In setup, serial communication is started on a baud rate of 115200, and the message start is sent to indicate to you that the serial port is connected:

void setup()
{
 
Serial.begin(115200);
Serial.println("start");

This commented line is not used in this sketch but is referenced in some of the other CapSense examples. It can be uncommented to include further calibration functions that are in the library but is not be covered in this example:

// slider_2_7.calibrateSlider();
 
}

In this sketch, many variables are declared locally. Because they’re not needed outside the loop, they’re removed after each loop and redeclared at the start of the next loop.

First, a one-millisecond delay occurs to help improve the stability of the reading:

void loop()
{
 
 
delay(1);

Next, the long variable total1 is declared. This variable can look confusing because the lowercase L and the numeral 1 look the same in most fonts. Incidentally, this variable is not used in this sketch. It may well be left over from a previous version:

 long total1 = 0;

The next long variable is set to the current millis () value. Because this variable is local, the value is reset on each loop:

 long start = millis();

The specific function .readPin() reads your capacitive pin:

 long total = cPin_5.readPin(2000);

If you want to explore in more depth what’s happening, look at CapPin.cpp in the CapSense library. At first, the CapPin.cpp file looks baffling, but by reading the line that follows, you can see that the value relates to the number of samples that the Arduino is taking of the capacitance reading:

strong>long CapPin::readPin(unsigned int samples)

Editing the inner workings of libraries is not advised for beginners, but it is good to have a look at them to know what’s happening in your code and try to gain a better understanding of them.

A smoothing function is also included in the sketch. This function takes the raw reading from the sensor, the smoothing value, and then the output variable. At present, the smoothing value is set to 0.8, but go ahead and experiment with this value to find the appropriate amount of smoothing for your application. This amount is dependent on how fast the loop is completed and how many readings are made in that time, so bear that in mind if you expect to add a lot of other controls or outputs:

// simple lowpass filter to take out some of the jitter
// change parameter (0 is min, .99 is max) or eliminate to suit
smoothed = smooth(total, .8, smoothed);

Finally, the values are printed to the serial port to be monitored. millis() – start gives the time that is taken to carry out the reading. If more samples are taken or any delays are added to the code, these activities increase the time to complete the loop and, therefore, the reaction time of the sensor:

Serial.print( millis() - start); // time to execute in mS

Tabs are used to neatly space the values. The total and smoothed values are both printed for comparison. You may notice a slight delay in the response time of the smoothed value. This delay shows you that your Arduino is reading many more values to do the smoothing, which takes time. This delay is barely noticeable when the sensor is in use because the baud rate is so high:

Serial.print("\t");
Serial.print(total);         // raw total
Serial.print("\t");
Serial.println((int) smoothed);    // smoothed
delay(5);
}

At the bottom of the sketch outside the main loop is an additional function, referred to as a lowpass filter, which gives you the smoothed result. You can see that rather than starting with void, as is the case in setup () and loop (), the function starts with int, which means that an integer value is returned. Starting with int indicates that this function returns an integer value rather than a floating-point value.

// simple lowpass filter
// requires recycling the output in the "smoothedVal" param
int smooth(int data, float filterVal, float smoothedVal){

 if (filterVal > 1){   // check to make sure param's are within range
  filterVal = .999999;
 }
 else if (filterVal <= 0){
  filterVal = 0;
 }

 smoothedVal = (data * (1 - filterVal)) + (smoothedVal * filterVal);

 return (int)smoothedVal;
}