Week 08 ~ input devices


Capacitive sensing

For my final project I wanto to make actuated velcro-like surfaces and it would be great if they had feedback about how far they have actuated/whether they have grabbed onto another surface.

Capacitive sensing sounds like it makes sense - I could add an extra conductive layer (copper tape) to the material and measure the change in capacitance as the surface is folded or as another surface approaches. I also got reminded of this research paper on integrating capacitive sensing into 3D printed metamaterials. It looks like there are a range of analog approaches to capacitive sensing, although the simplest approach using a microcontroller seems to be an RC circuit where you measure the time it takes for a circuit to respond to an input voltage, via the time constant t = RC. This can be done via two pins (one for sending the pulse, the other for reading the response of the circuit).

Responsive image
Schematic in KiCad - I added extra pads to adjust the R and C values of the circuit.
Responsive image
Responsive image
Milled board with soldered components; actual way I adjusted the resistance ...
Responsive image
Making a capacitive sensor using copper tape: zig-zag faces will be connected in an alternating fashion to form two halves of a capacitor (i.e. half the faces will be connected to the sensor pin, the other half to ground)
Responsive image
Reverse side of the sensor with connections to the milled circuit board.
Responsive image
Compressing the sensor should raise the capacitance, C ~ A / d (where d = distance between plates, A = area overlap), increasing the time it takes for the sensor pin to react to the signal pin, via the time constant t = RC).
Responsive image
With an oscilloscope hooked up to the ground and sensor pin, using the 'trigger' function to capture the discharge through the sensor.
Responsive image
Zig-zag surfaces meshed together (with cavities to place copper foil?)
Responsive image
Two flexible surfaces with copper-foil backing - one connected to ground, the other to the sensor pin. Using a wooden stick to isolate the test from 'human capacitance'.
Test weith two surfaces (video).
Responsive image
Serial plot of two plates test; integrating David's low-pass filter code. The dip in the plot is when the two plates are touching: bringing the top plate back up, brought the value back up the original value (or close to!)
      
        #include 
          CapacitiveSensor   cs_4_2 = CapacitiveSensor(4,2);        // 10M resistor between pins 4 & 2, pin 2 is sensor pin, add a wire and or foil if desired
          
          
          // Variables
            float reading = 0;
            float tare = 0;
          
          // Variables for Averaging
            const int totalSamples = 10;
            int index_avg = 0;
            int value = 0;
            float sum = 0;
            int readings[totalSamples]; // create an empty array of size totalSamples
          
          // Variables for Low Pass
            float filteredOutputPrevious = 0;
            const float RC = 0.100;
            const float dT = 0.01; // time in seconds
            const float C1 = dT/(RC+dT); // coefficient 1
            const float C2 = RC/(RC+dT); // coefficient 2
          
            float capsensor_output;
          
          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_2.capacitiveSensor(30);
          
              Serial.print(millis() - start);        // check on performance in milliseconds
              Serial.print("\t");                    // tab character for debug windown spacing
              capsensor_output = total1;
              // Serial.println(total1);                  // print sensor output 1
          
              //delay(10);                             // arbitrary delay to limit data to serial port 
          
              //float filtered_reading = batchAverageRead() - tare;             // Batch average reading
              //float filtered_reading = movingAverageRead()  - tare;           // Moving average read
              float filtered_reading = lowPassRead()  - tare;                   // Low pass read
              Serial.println(filtered_reading);                                 // send our reading over USB to the computer
              delay(dT*1000);                                                   // delay between reads in miliseconds (necessary for low pass)
          }
          
          // Batch Averaged sensor reading ----------------------------------------------------
          float batchAverageRead(){
              sum = 0;
              for (int i = 0; i < totalSamples; i++){
                  sum = sum + capsensor_output;                           // sum totalSamples readings
                  delay(dT*1000);                                                    // wait for every reading! This is bad :(
              }
              return sum / totalSamples;
          }
          
          
          // Moving Average sensor reading ----------------------------------------------------
          float movingAverageRead(){
              sum = sum - readings[index_avg];                            // Remove the oldest entry from the sum
              value = capsensor_output;                              // Read the next sensor value
              readings[index_avg] = value;                                // Add the newest reading to the window
              sum = sum + value;                                          // Add the newest reading to the sum
              index_avg = (index_avg+1)%totalSamples;                     // Increment the index, and wrap to 0 if it exceeds the window size
              return sum/(float(totalSamples));                           // Divide the sum of the window by the window size for the result
          }
          
          // Low Pass Filter sensor reading -------------------------------------------------
          float lowPassRead(){
              float filteredOutput = capsensor_output*(C1) + filteredOutputPrevious*(C2);  // All we need to do here is to measure once and do some fast multiplication with our coefficients! This is great :)
              filteredOutputPrevious = filteredOutput;                                          // And store our output for next time
              return filteredOutput;
          }