Introduction: Touchless Keypad: DIY Capacitive Proximity Sensors With Aluminium Foil & Capacitive Sensing Library

Touch interfaces such as elevators buttons can potentially aid in the transmission of pathogens. Inspired by the COVID-19 pandemic, I decided to build a prototype of touchless keypad. By implementing Arduino Capsense Library, capacitive proximity sensors are made with aluminium foil and high value resistors. As this setup normally functions as a touch sensing device, several modifications are implemented to increase the sensor's sensitivity for proximity sensing, which will be highlighted in this article.

Step 1: How Does It Work?

A finger, which has high dielectric properties, is able to increase the capacitance. If the capacitance of a RC circuit is higher, the time taken to charge or discharge is longer, which can be detected by Arduino. It is recommended that you read this article (https://playground.arduino.cc/Main/CapacitiveSensor/) which explains the mechanism and library methods in details.

Step 2: Tools & Materials

(1) Arduino UNO
(2) Breadboard
(3) 10M Ohm Resistors × 11
(4) Male-to-male/Male-to-female connector x 11
(5) Male-to-male connectors × 13
(6) Aluminium foil
(7) OLED display
(8) Standing calendar
(9) Scissor and cellophane tape
(10) Stripping pliers (optional)

Step 3: Attaching Aluminium Foil

Sketch the outline on the calendar. Use a small screw (or something sharp) to make a small hole. After stripping the insulator off the wire, attach the exposed wire to the aluminium foil.

Note: As Arduino UNO has a limited number of input pins, only 11 out of the 12 foil pieces can be used as capacitive sensors. You will be able to cover every digit from 0 to 9, and an extra input to clear/delete.

Step 4: Wiring & Attaching OLED Display

Further details and explanation on how to use an OLED module can be found in https://randomnerdtutorials.com/guide-for-oled-display-with-arduino/

Step 5: Code

#include <CapacitiveSensor.h>
const byte howManySensors = 11; // total number of capacitive sensor input
int sensorsVal[howManySensors]; // declare an array to store all input
const byte threshold = 200; // Setting a threshold based on your observation

// 10 megohm resistor between pins 13 & 12, pin 12 is the receiver pin, add wire, foil
// multiple sensors can share the same sender pin 13
CapacitiveSensor cs_13_12 = CapacitiveSensor(13,12); 
CapacitiveSensor cs_13_11 = CapacitiveSensor(13,11);
CapacitiveSensor cs_13_10 = CapacitiveSensor(13,10);
CapacitiveSensor cs_13_9 = CapacitiveSensor(13,9);
CapacitiveSensor cs_13_8 = CapacitiveSensor(13,8);
CapacitiveSensor cs_13_7 = CapacitiveSensor(13,7);
CapacitiveSensor cs_13_6 = CapacitiveSensor(13,6);
CapacitiveSensor cs_13_5 = CapacitiveSensor(13,5);
CapacitiveSensor cs_13_4 = CapacitiveSensor(13,4);
CapacitiveSensor cs_13_3 = CapacitiveSensor(13,3);
CapacitiveSensor cs_13_2 = CapacitiveSensor(13,2);

/**
Setting Up OLED Display
**/

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels

// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);


void setup(){
  // set autocalibration
  cs_13_12.set_CS_AutocaL_Millis(5000);
  cs_13_11.set_CS_AutocaL_Millis(5000);
  cs_13_10.set_CS_AutocaL_Millis(5000);
  cs_13_9.set_CS_AutocaL_Millis(5000);
  cs_13_8.set_CS_AutocaL_Millis(5000);
  cs_13_7.set_CS_AutocaL_Millis(5000);
  cs_13_6.set_CS_AutocaL_Millis(5000);
  cs_13_5.set_CS_AutocaL_Millis(5000);
  cs_13_4.set_CS_AutocaL_Millis(5000);
  cs_13_3.set_CS_AutocaL_Millis(5000);
  cs_13_2.set_CS_AutocaL_Millis(5000);
  
  Serial.begin(9600);
  
  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3C for 128x64
    Serial.println(F("SSD1306 allocation failed"));
    for(;;);
  }
  delay(2000);
  
  display.clearDisplay();
  display.setTextSize(2);
  display.setTextColor(WHITE);
  display.setCursor(0, 10);
  // Display static text
  display.println(F("Initialising..."));
  display.display(); 
  
}

void loop(){
  // The intended number should correspond to the index number
  // Match the correct physical pin "cs_xx_xx.capacitiveSensor()" to the correct index
  // Index 0 --> number 0, Index 1 --> number 1, and so on
  // Index 10 --> an extra button
  sensorsVal[0] = cs_13_11.capacitiveSensor(130);
  sensorsVal[1] = cs_13_2.capacitiveSensor(130);
  sensorsVal[2] = cs_13_3.capacitiveSensor(130);
  sensorsVal[3] = cs_13_4.capacitiveSensor(130);
  sensorsVal[4] = cs_13_5.capacitiveSensor(130);
  sensorsVal[5] = cs_13_6.capacitiveSensor(130);
  sensorsVal[6] = cs_13_7.capacitiveSensor(130);
  sensorsVal[7] = cs_13_8.capacitiveSensor(130);
  sensorsVal[8] = cs_13_9.capacitiveSensor(130);
  sensorsVal[9] = cs_13_10.capacitiveSensor(130);
  sensorsVal[10] = cs_13_12.capacitiveSensor(130);

  // return error when it takes too long

  int maxVal = 0; // To find the max value of sensorsVal[] array
  byte maxValIndex = 0; // To find the index of the max value of sensorsVal[] array

  for(byte i = 0; i < howManySensors; i++){
    /**
    // UNCOMMENT THIS TO DEBUG
    // use serial plotter to choose a threshold value
    Serial.print(sensorsVal[i]);
    Serial.print("\t");
    **/
    
    // To find the max value of the array
    if(sensorsVal[i] == -2){
      maxVal = sensorsVal[i]; //locate timeout condition
      break;
    }
    else if(sensorsVal[i] > maxVal){
      maxVal = sensorsVal[i];
      maxValIndex = i;
    }
  }
  Serial.print("\n"); 

  
  if(maxVal > threshold){
    Serial.println(maxValIndex);
    oledDisplay(maxValIndex);
    delay(500); // to prevent multiple entries
  }
  else if(maxVal == -2){
    // CapacitiveSensor returns -2 when there is timeout due to bad connection
    oledDisplay(255);
    delay(500);
  }
  
  delay(10); // arbitrary delay to limit data to serial port
  
}


void oledDisplay(byte val){
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(25, 5);
  // Display static text
  display.println(F("The number is:"));
  if(val == 10){
    // clear number
    display.display();
  }
  else if (val == 255){
    // sending error message
    display.setCursor(0, 20);
    display.println(F("Connection error"));
    display.display();
  }
  else{
    // display the number
    display.setTextSize(5);
    display.setCursor(53, 20);
    display.println(val);
    display.display();
  }
}<br>

You'll need to install the Capacitive Sensor Library by Paul Badger. You may also wish to download the relevant library for the OLED display.

Step 6: Final Product

The following methods are used to improve the sensitivity & accuracy

(1) set_CS_AutocaL_Millis(5000)
Re-calibration is set at a 5-second interval
(2) capacitiveSensor(130)
By experimenting, the optimum sampling rate is found to be 130. You may wish to try different values.
(3) Ground plate
To improve grounding, a large piece of aluminium foil is mounted on the sides of calendar, which is connected to the ground pin of Arduino. Refer to the note on the second diagram.