Introduction: Lowering Capacitive Sensor Fluctuation in RGB Led Proximity

About: Always up for something new!

This is a fairly specific Instructable on how to embed a capacitive sensor in close proximity of other wires, here an RGB led. As part of a project I'm working on, I want to control an RGB led through a capacitive sensor. However, there's a problem: Blue and Green draw more power than Red, and the induction (I think) created by these electric flows influences the capacitive sensor. The solution presented below can be applied to anything else as well by simply swapping "color spectrum" for "possible states of the device", such as decibels on a speaker.

While I'm reading values from 0-2000 for "hand closeby" values, the readings fluctuate between 0 and 1000 depending on the color nearby LEDs are emitting (the power they're drawing). On the graph above, the horizontal axis represents all the colors of the color spectrum, while the vertical axis represents the values the capacitive sensor reads while nothing is nearby. The blue line represents these "steady state" readings. The highest spike is Cyan, where both Green and Blue are activated. Obviously, this at first seemingly random fluctuation makes any kind of control through nearby gestures impossible.

The orange line in the graph is the standard deviation, which comes in around 0.5%, indicating the fluctuations are definitely caused by the color spectrum and not thus are not all that random.

One solution would be to disable the led for a few milliseconds, measure, and re-enable it; but that diminishes the light output, so there must be a better solution. Instead, we'll set up an array of values to substract from the readings, depending on the color currently being emitted. This will effectively stabilize the readings output without affecting the led output.

Step 1: Collect Data by Cycling Through the Color Spectrum

For this instructable I'm using the Arduino code supplied in this instructable:

https://www.instructables.com/id/How-to-Make-Prope...

Which uses a sine wave to cycle through the color spectrum. If you have your own code, that works just as well.

First, we'll collect a data sample through the serial monitor. Hook up your project and print the following in the serial monitor:

  • Color value that counts 1 per step in your color cycling code, here going from 1 to 360.
  • The measured value from your Capacitive Sensor

Now let your project cycle through all the colors a couple times. I ended mine after 100 iterations. Copy everything into an excel file, place the readings next to eachother by color and average them. Then map these values into a graph and voila! You have yourself all the erratic capacitive sensor values caused by the current differences along the color spectrum. You could do this by hand, but this bit of excel macro significantly eases the process (assuming you pasted 100x360 color values in column A and pasted measured values in column B) :

Sub Macro1()

Dim k As Long

For k = 1 To 100 Range("B" & ((k * 360) + 1) & ":" & "B" & ((k * 360) + 360)).Select Selection.Cut Range("B1").Offset(0, 1).Select ActiveSheet.Paste Next End Sub

Step 2: Correcting Your Readings in Arduino Code

Now that we have the exact values of the error, we can simply substract them from our Capacitive sensor readings and the result will be very close to a nice, straight line around zero. As you can see in the first graph, the standard deviation of my 100 readings is ~0.5%, so the line will mostly fluctuate between -50 and +50.

To substract them, set up an array of the averages of the readings:

const uint16_t K_values[360]={
110, 112, 114, 116, 119, 121, 122, 124, 125, 126, 127, 127, 126, 125, 124, 123, 122, 120, 119, 117, 116, 116, 116, 116, 116, 118, 120, 123, 126, 130, 135, 141, 149, 157, 166, 176, 186, 197, 208, 220, 234, 249, 264, 281, 297, 312, 327, 338, 349, 363, 374, 383, 392, 401, 411, 415, 418, 420, 423, 425, 424, 419, 420, 423, 423, 425, 426, 428, 427, 424, 422, 421, 422, 421, 419, 418, 421, 419, 417, 412, 407, 403, 396, 386, 380, 372, 362, 351, 338, 326, 314, 302, 288, 272, 258, 244, 229, 217, 206, 194, 182, 172, 161, 151, 143, 135, 127, 121, 116, 111, 106, 103, 101, 99, 99, 98, 99, 101, 104, 106, 109, 111, 114, 116, 119, 120, 121, 123, 124, 124, 123, 121, 119, 116, 112, 109, 106, 103, 99, 96, 93, 91, 88, 87, 86, 86, 88, 91, 95, 100, 105, 111, 116, 123, 132, 141, 152, 163, 175, 186, 199, 212, 225, 238, 254, 279, 311, 341, 386, 428, 477, 527, 577, 628, 678, 729, 781, 833, 884, 931, 968, 998, 1029, 1044, 1059, 1067, 1074, 1079, 1081, 1078, 1071, 1062, 1053, 1040, 1024, 1004, 978, 939, 894, 846, 796, 748, 693, 643, 596, 548, 499, 451, 404, 359, 317, 283, 259, 241, 227, 213, 197, 186, 172, 160, 149, 138, 127, 119, 113, 108, 102, 98, 96, 92, 91, 90, 90, 92, 94, 97, 101, 104, 107, 111, 113, 116, 119, 122, 124, 127, 128, 129, 128, 128, 126, 125, 122, 120, 116, 114, 111, 108, 105, 102, 100, 98, 97, 97, 98, 99, 101, 102, 104, 107, 109, 112, 115, 119, 123, 128, 133, 137, 143, 148, 155, 163, 172, 182, 194, 206, 219, 230, 241, 253, 262, 272, 283, 293, 303, 312, 319, 325, 331, 334, 338, 335, 337, 340, 342, 346, 348, 349, 349, 348, 347, 345, 342, 339, 336, 331, 332, 330, 325, 319, 313, 304, 294, 285, 276, 264, 253, 243, 233, 222, 212, 201, 190, 180, 170, 159, 152, 146, 140, 134, 129, 124, 120, 116, 112, 109, 107, 104, 102, 100, 99, 98, 98, 97, 98, 99, 101, 103, 106, 109};

Then while you're cycling through the color spectrum, in the following code, "k" is the time value cycling from 0 to 360 indicating what color is currently being projected by the LED. So simply substract them:

long CurrentReading = 0;
long ProjectedReading =0;


void loop() {

for (int k=0; k<360; k++){ CurrentReading = CSMain.capacitiveSensor(20); //take the current reading

ProjectedReading= constrain ( CurrentReading-K_values[k],0,20000); //substract the averaged value you measured at this color "k" from the current reading at this color "k"

sineLED(0, k); // Activate your LED for color k delay(30); // Delay for nicer color cycling }}

I'm constraining the values overall to zero because negative values are useless fluctuation to my project and generally just difficult to work with. You might slap on an extra -100 to account for the standard deviation.

I should note that for both the K_values readings and the CurrentReadings, I'm smoothing the past ten results into one by averaging them, because this gives a better stability level imo. This isn't really necessary, but I find it helpful. The code for that can be found here: https://www.arduino.cc/en/Tutorial/Smoothing

Also, if your project is short on memory, these arrays take up a lot of space. You can sacrifice some detail to win space by dividing everything over 5 (mapping them to values below 256) and using an 8bit array instead of a 16bit array; after which you remultiply the values in your code. Don't think this would impact performance.

That's it! Enjoy your now stable readings!