Arduino capacitive sensor and the friction drum
I recently cut out a capacitive sensor on my old CNC machine for a friend working at the university. They plan to connect the sensor to Raspberry PI and try to make a virtual friction drum.
The sensor is pretty simple – it’s made of several rectangular copper sensing planes which are connected to wires. I drew the cut lines directly in CamBam and used the gcode on the CNC mill to cut it out. The main issue of the home-made capacitive sensors is that you will need to solder some connecting wires to the capacitive sensing plates, which may in some applications interfere with the use of sensor. On a doublesided PCB the connection tracks could be routed on the back side of the sensor and the sensor PCB would have no “soldering bumps”. Another issue is that there is no stop mask which would prevent the user to touch the sensing elements directly, but this can be easily remedied by covering the sensing PCB with some sort of isolating material or by painting it. If you make an actual electric contact with a capacitive sensor (eg. touching the sensing plate directly, with no isolator) it will usually perform badly, especially in sensor with multiple sensing elements.
This version of the sensor will be used for a proof-of-concept work and will probably be replaced by professionally made PCB later. Also the layout of sensing areas will probably be changed to a V / zigzag pattern to increase the linearity of position sensing between two adjacent sensing areas. For some nice capacitive sensor layouts you can check this link – it’s actually a manual for software which generates the layouts, but you can check out the images. If you are interested in these designs you should probably also check the original atmel papers on them.
As I was going to deliver the sensor the next day I didn’t have time to try connecting it to RPi, however I did connect it to arduino to see how it performs.
Before jumping to the arduino code just a quick look at how the capacitive sensing libraries work. Capacitive sensor is basically a variable capacitor. When a conductive object – like a person’s finger comes near sensor, the capacitance gets higher. The libraries used here charge / discharge the capacitor through a large resistor and measure the time it takes to charge / discharge a capacitor to a certain level. The time constant is related to the capacitance – the larger the capacitance, the longer it will take to charge to a certain level.
Here you can see a simulation of a charge / discharge cycle of a few different values of capacitors. Capacitors of 100-300 pF are connected through 10meg resistors. Cyan graph is the input voltage, red (100p), green (200p) and blue (300p) graphs are the voltages on capacitors. It can easily be observed that the bigger the capacitor the longer it takes to charge to a specified value (eg. to 2.5V).
Note that there are also many other ways to measure small capacitances (eg. charge distribution, capacitance to frequency conversion, different bridge implementations), which may be better under some circumstances.
There are basically two available capacitive sensing libraries for arduino.
http://playground.arduino.cc/Code/CapacitiveSensor
and
http://playground.arduino.cc/Main/CapacitiveSensor?from=Main.CapSense
The first one is “nice” as it uses internal resistors (weak pullup resistors) to do the measuring, which means that there is no external resistors needed for operation – you simply connect the sensing pads to the arduino pins. I quickly edited the code to display multiple inputs.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 |
/* Read multiple capacitive sensors and output the measured values. based on: http://playground.arduino.cc/Code/CapacitiveSensor edited by dejko1, Apr 2015 */ // readCapacitivePin // Input: Arduino pin number // Output: A number, from 0 to 17 expressing // how much capacitance is on the pin // When you touch the pin, or whatever you have // attached to it, the number will get higher #include "pins_arduino.h" // Arduino pre-1.0 needs this uint8_t readCapacitivePin(int pinToMeasure) { // Variables used to translate from Arduino to AVR pin naming volatile uint8_t* port; volatile uint8_t* ddr; volatile uint8_t* pin; // Here we translate the input pin number from // Arduino pin number to the AVR PORT, PIN, DDR, // and which bit of those registers we care about. byte bitmask; port = portOutputRegister(digitalPinToPort(pinToMeasure)); ddr = portModeRegister(digitalPinToPort(pinToMeasure)); bitmask = digitalPinToBitMask(pinToMeasure); pin = portInputRegister(digitalPinToPort(pinToMeasure)); // Discharge the pin first by setting it low and output *port &= ~(bitmask); *ddr |= bitmask; delay(1); uint8_t SREG_old = SREG; //back up the AVR Status Register // Prevent the timer IRQ from disturbing our measurement noInterrupts(); // Make the pin an input with the internal pull-up on *ddr &= ~(bitmask); *port |= bitmask; // Now see how long the pin to get pulled up. This manual unrolling of the loop // decreases the number of hardware cycles between each read of the pin, // thus increasing sensitivity. uint8_t cycles = 17; if (*pin & bitmask) { cycles = 0;} else if (*pin & bitmask) { cycles = 1;} else if (*pin & bitmask) { cycles = 2;} else if (*pin & bitmask) { cycles = 3;} else if (*pin & bitmask) { cycles = 4;} else if (*pin & bitmask) { cycles = 5;} else if (*pin & bitmask) { cycles = 6;} else if (*pin & bitmask) { cycles = 7;} else if (*pin & bitmask) { cycles = 8;} else if (*pin & bitmask) { cycles = 9;} else if (*pin & bitmask) { cycles = 10;} else if (*pin & bitmask) { cycles = 11;} else if (*pin & bitmask) { cycles = 12;} else if (*pin & bitmask) { cycles = 13;} else if (*pin & bitmask) { cycles = 14;} else if (*pin & bitmask) { cycles = 15;} else if (*pin & bitmask) { cycles = 16;} // End of timing-critical section; turn interrupts back on if they were on before, or leave them off if they were off before SREG = SREG_old; // Discharge the pin again by setting it low and output // It's important to leave the pins low if you want to // be able to touch more than 1 sensor at a time - if // the sensor is left pulled high, when you touch // two sensors, your body will transfer the charge between // sensors. *port &= ~(bitmask); *ddr |= bitmask; return cycles; } // digital pin 2 has a pushbutton attached to it. Give it a name: int pushButton = 2; // the setup routine runs once when you press reset: void setup() { // initialize serial communication at 9600 bits per second: Serial.begin(9600); // make the pushbutton's pin an input: pinMode(pushButton, INPUT); } // the loop routine runs over and over again forever: void loop() { // read the input pin: int buttonState = digitalRead(pushButton); // print out the state of the button: Serial.print(buttonState); Serial.print(" "); Serial.print(readCapacitivePin(8)); Serial.print(" "); Serial.print(readCapacitivePin(9)); Serial.print(" "); Serial.print(readCapacitivePin(10)); Serial.print(" "); Serial.print(readCapacitivePin(11)); Serial.print(" "); Serial.print(readCapacitivePin(12)); Serial.println(); delay(1); // delay in between reads for stability } |
Sensing pads were connected directly to pins 8-12 on arduino.
Sensing board was covered with thin transparency film to avoid direct contact with the pins. The resolution however is quite terrible, I only got a few values of change when I pressed against sensing pads.
Here you can see the terminal window of arduino showing the measured values. The last five number in each row are displaying the returned value of each capacitive sensor. The middle capacitive sensing pad is touched for the result on the image. You can get a much more pronounced response if you directly touch the sensing pads, but the results are not really usable as also the neighbouring pads will change value…
Next I modded the capsense example
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
#include <CapacitiveSensor.h> /* Read multiple capacitive sensors and output the measured values. * based on: CapacitiveSense Library Demo Sketch by Paul Badger 2008, http://playground.arduino.cc/Main/CapacitiveSensor?from=Main.CapSense * edited by dejko1, Apr 2015 */ CapacitiveSensor cs_4_8 = CapacitiveSensor(4,8); // 10M resistor between pins 4 & 2, pin 2 is sensor pin, add a wire and or foil if desired CapacitiveSensor cs_4_9 = CapacitiveSensor(4,9); // 10M resistor between pins 4 & 6, pin 6 is sensor pin, add a wire and or foil CapacitiveSensor cs_4_10 = CapacitiveSensor(4,10); // 10M resistor between pins 4 & 8, pin 8 is sensor pin, add a wire and or foil CapacitiveSensor cs_4_11 = CapacitiveSensor(4,11); // 10M resistor between pins 4 & 6, pin 6 is sensor pin, add a wire and or foil CapacitiveSensor cs_4_12 = CapacitiveSensor(4,12); // 10M resistor between pins 4 & 8, pin 8 is sensor pin, add a wire and or foil void setup() { //cs_4_2.set_CS_AutocaL_Millis(0xFFFFFFFF); // turn off autocalibrate on channel 1 - just as an example Serial.begin(9600); } void loop() { long start = millis(); long total1 = cs_4_8.capacitiveSensor(30); long total2 = cs_4_9.capacitiveSensor(30); long total3 = cs_4_10.capacitiveSensor(30); long total4 = cs_4_11.capacitiveSensor(30); long total5 = cs_4_12.capacitiveSensor(30); Serial.print(millis() - start); // check on performance in milliseconds Serial.print("\t"); // tab character for debug windown spacing Serial.print(total1); // print sensor output 1 Serial.print("\t"); Serial.print(total2); // print sensor output 2 Serial.print("\t"); Serial.print(total3); // print sensor output 3 Serial.print("\t"); Serial.print(total4); // print sensor output 2 Serial.print("\t"); Serial.println(total5); // print sensor output 3 delay(10); // arbitrary delay to limit data to serial port } |
And breadboarded the resistors needed for the library:
Capacitive sensors are connected to arduino pins 8-12, pin 4 is used for excitation. Resistors are connected between pin 4 and each of the sensing pads. 4,7M resistors were used. This library gives much better resolution in terms of value change when an object is near the sensor. You can influence the resolution by substituting resistors with bigger (more resolution) or smaller values (less resolution). It should also be noted that it takes a bit longer to get the result with better resolution.
The next day after testing I delivered the sensor to the lab, so hopefully it will be of some use for them. I will post here if I get some interesting feedback from them, so stay tuned 😉
Leave a Reply