Identify succession of 4 sensor inputs within a variable interval

Hi everyone,

This is my first post on this forum, so if I am not providing all the information necessary to answer my question, please let me know.

I am building a circuit to identify a swipe movement across 4 capacitive sensors. I made these sensors out of conductive copper tape and sealed them with scotch tape. They are connected to my Arduino Mega 2560. (See schematic in attachment).

I managed to register a swipe movement, but only within a specific time interval. I have now used delay but I realize it’s maybe better to switch to millis(). What I would want, is that it can recognize all swipe movements that are executed within for example 10 seconds. So instead of measuring an interval between two successive sensors, it should identify whether the total swipe movement is completed within those 10 seconds. If possible, it would be nice if not all sensors had to be touched in order for it to work - so swiping between sensor 1 and 3 is also registered.

For now, I want led1 to glow if the swipe direction is from sensor 1 to sensor 4, and led2 to glow if the swipe goes in the reversed direction.

Here is the code I have:

#include <CapacitiveSensor.h>

CapacitiveSensor   cs_4_2 = CapacitiveSensor(4,2);        // 10 megohm resistor between pins 4 & 2, pin 2 is sensor pin, add wire, foil
CapacitiveSensor   cs_4_5 = CapacitiveSensor(4,5);        // 10 megohm resistor between pins 4 & 5, pin 5 is sensor pin, add wire, foil
CapacitiveSensor   cs_4_8 = CapacitiveSensor(4,8);        // 10 megohm resistor between pins 4 & 8, pin 8 is sensor pin, add wire, foil
CapacitiveSensor   cs_4_10 = CapacitiveSensor(4,10);      // 10 megohm resistor between pins 4 & 10, pin 10 is sensor pin, add wire, foil

const int ledPin1 = 53;
const int ledPin2 = 52;

int SensorValue = 0;      
int prevSensorValue = 0;
int prevprevSensorValue = 0;

void setup() {
// turn off autocalibrate
cs_4_2.set_CS_AutocaL_Millis(0xFFFFFFFF);     
cs_4_5.set_CS_AutocaL_Millis(0xFFFFFFFF);     
cs_4_8.set_CS_AutocaL_Millis(0xFFFFFFFF);
cs_4_10.set_CS_AutocaL_Millis(0xFFFFFFFF);

pinMode(ledPin1, OUTPUT);
pinMode(ledPin2, OUTPUT);
Serial.begin(9600);

}

void loop() {


    long start = millis(); //copied from the capacitive library
    long total1 =  cs_4_2.capacitiveSensor(30);
    long total2 =  cs_4_5.capacitiveSensor(30);
    long total3 =  cs_4_8.capacitiveSensor(30);
    long total4 =  cs_4_10.capacitiveSensor(30);

    // Set tresholds for absolute touch. When 1000 or higher, the sensor is touched. 
    //The sensors next to the touched sensor give higher values. 
    //Only one sensor can be touched at the same time.
    // Assign different value to every sensor when touched
    if (total1 > 1000 && total2 < 900 && total3 < 600 && total4 <600){
      SensorValue = 1;
    }
  
   else if (total2 > 1000 && total1 < 900 && total3 < 900 && total4 <600){
      SensorValue = 2;
    }
   
    else if (total3 > 1000 && total1 < 600 && total2 < 900 && total4 <900){
      SensorValue = 3;
    }
    
     else if (total4 > 1000 && total1 < 600 && total2 < 600 && total3 <900){
      SensorValue = 4;
    }
    else   {
     SensorValue = 0;
         }

 // In order to detect a swipe including direction, the difference between the assigned values is calculated. 
    // For a direction high to low, the difference between the previous value and the current value should be -1
    // To enable two different swiping speeds, the current value can also be compared to the value previous to the previous value
    if (SensorValue == (prevSensorValue + 1) || SensorValue == (prevprevSensorValue + 1)) {
       digitalWrite(ledPin1, HIGH);
       digitalWrite(ledPin2, LOW);
       
    }
     
      
  else  if (SensorValue == (prevSensorValue - 1)|| SensorValue == (prevprevSensorValue - 1)) {
      digitalWrite(ledPin2,HIGH);
      digitalWrite(ledPin1, LOW);
      
    }
      else {
     digitalWrite(ledPin2, LOW);
     digitalWrite(ledPin1, LOW);
      }

Serial.print(total1);                  // print sensor output 1
    Serial.print("\t");
    Serial.print(total2);                  // print sensor output 2
    Serial.print("\t");
    Serial.print("\t");
    Serial.print(total4);
    Serial.print("\t");
    Serial.println(SensorValue);

delay(200);                             // arbitrary delay to limit data to serial port 

    prevSensorValue = SensorValue;
    prevprevSensorValue = prevSensorValue;
  }

Any ideas to improve my code? Even if you can only help me a little bit further, it would really help me!

Thanks in advance.

circuit capacitief prototype (1).png

I have now used delay but I realize it's maybe better to switch to millis().

Not just better, mandatory.

Each time that a sensor registers contact, record the time. Whenever appropriate, look at all the times, when there are two or more non-zero times. Determine if they are within the range of interest. If not, clear the times. If they are, then the relationship between the times (time two is greater than time one, or it isn't) defines the swipe direction. You project is more complicated in that you want to allow some sensors to be skipped, but not that much more.

I suspect what you need to do is record the time when each sensor is touched - perhaps record the value of micros() whenever a sensor detects something.

Then at the end of your chosen interval (10 seconds seems incredibly long) you can review the recorded times and figure out the order they were touched as well as whether they were touched.

And, yes, delay() is quite inappropriate.

The demo Several Things at a Time illustrates the use of millis() to manage timing. The same technique works with micros() if required.

…R

Thank you for your quick repllies.

I will try to implement your suggestions keep you updated on how it works after modification.

@Robin2: I just found that demo and will implement it right away!
10 seconds is probably too long indeed, I still have to test the ideal time span.

Hello guys,

I managed to fix my code in order for it to work properly.
First I tried to record the times when each sensor was touched and said that, when the difference between two values was <= a certain interval, it should put the led ON. Somehow, this did not work properly, so I tried something else.

These are the changes I’ve made:

  • Implement millis() instead of delay()
  • in the conditions for sensor values, leave out the values of the sensors right next to the touched sensor. Since the sensors are placed quite close to each other, both will be touched when moving from one sensor to another. My previous code prevented the led to stay on while two sensors were touched at the same time, resulting in blinking.
if ((unsigned long) currentMillis - previous_Sensor_Millis >= MaxInterval) { 
    if (total1 > 800 && total3 < 600 && total4 <600 && total5 <600 && total6 <600 && total7 <600){
      SensorValue = 1;
    }
  • If the touch of one sensor is not recognized, I did not want the led to stop glowing, so I added the option of having a difference of +/-2 with the prev prev value.
 if (SensorValue != 0){
    if (SensorValue == (prevSensorValue + 1) || SensorValue == (prevprevSensorValue + 1) || SensorValue == (prevprevSensorValue + 2)) {
       digitalWrite(ledPin1, HIGH);
       digitalWrite(ledPin2, LOW);
      }

Somehow, this new code also fixes the problem of a constant velocity, and it allows for the led to keep burning when the swipe movement ends as long as the last sensor of the swipe movement is still being touched. I think because I left the sensor values next to the touched sensor out, at some points two sensor value conditions apply, making the sensor value both 1 and 2, and thus the difference between the value and the previous value 0 and 1 at the same time. I’m not sure if this is why it works now, but this is my best guess.

Anyway, thanks for helping me out! It really helped to hear your opinions - made me look at it in a different way.

Hi, I would be greatful if you can share final code? I'm also working on this kind of code but not succesfull and can't manage to get it work properly.

Thanks!

Hi,

The changes I made to my code are already in my reply. So if you check out my initial code you can see the changes I made. Also, as I saw in the personal message you send me, it made it clear for me that you want another functionality. What is your code and what are the problems that you encounter?

If I understood you correctly, you want the LEDs to go on when you swipe in one direction and off when you swipe in the other direction. Does the initial swipe direction matter or do you want a state change regardless of the first swipe direction?

Hi,

thanks for reply, I think functionality should be te same as yours. Only difference is that you are turning LED1 in one swipe direction and in other direction turning LED1 OFF and LED2 ON. As I understood that. And I’m using only one. Initial swipe dirrection should matter
.
Does your code change state regardless of first swipe?

I copied your code, update it with millis() (hope that it right) and currently it do like that it:
1.) If I swipe in direction left->right it turns LED ON.
1.1) If I perform first start in other direction right-> left LED blinks.
2.) If then I swipe in opposite direction right->left it turns LED OFF.
3.) If then I “click” on what ever sensor (only 1) LED turns ON again…

Your code with corrections. Does it really works (or should) as above mentioned steps or did I defined something wrong?

#include <CapacitiveSensor.h>
CapacitiveSensor cs_4_8 = CapacitiveSensor(4,8); // 1M resistor between pins 4 & 8, pin 8 is sensor pin, add a wire and or foil
CapacitiveSensor cs_4_10 = CapacitiveSensor(4,10); // 1M resistor between pins 2 & 10, pin 8 is sensor pin, add a wire and or foil
CapacitiveSensor cs_4_9 = CapacitiveSensor(4,9); // 1M resistor between pins 3 & 9, pin 8 is sensor pin, add a wire and or foil

int SensorValue = 0;      
int prevSensorValue = 0;
int prevprevSensorValue = 0;
long previous_Sensor_Millis = 0;
long MaxInterval= 50;

void setup()
{
cs_4_8.set_CS_AutocaL_Millis(0xFFFFFFFF);// turn off autocalibrate on channel 1 - just as an example
cs_4_10.set_CS_AutocaL_Millis(0xFFFFFFFF);// turn off autocalibrate on channel 1 - just as an example
cs_4_9.set_CS_AutocaL_Millis(0xFFFFFFFF);// turn off autocalibrate on channel 1 - just as an example

Serial.begin(9600);
pinMode(13,OUTPUT);
}
void loop()
{

long currentMillis = millis();
long sensor1 = cs_4_8.capacitiveSensor(50);
long sensor2 = cs_4_9.capacitiveSensor(50);
long sensor3 = cs_4_10.capacitiveSensor(50);



if ((unsigned long) currentMillis - previous_Sensor_Millis >= MaxInterval) { 
if(sensor1 > 9000 && sensor2 < 5000 && sensor3 < 5000)

{
  SensorValue = 1;
}

else if(sensor2 > 9000 && sensor1 < 5000 && sensor3 < 5000)
{
  SensorValue = 2;
}

else if(sensor3 > 9000 && sensor2 < 5000 && sensor1 < 5000)
{
  SensorValue = 3;
}

//else
//{
  //SensorValue = 0;
//}

}

if (SensorValue != 0){
    if (SensorValue == (prevSensorValue + 1) || SensorValue == (prevprevSensorValue + 1) || SensorValue == (prevprevSensorValue + 2)) 
      {
       digitalWrite(13, HIGH);
             
    }
    
   else  if (SensorValue == (prevSensorValue - 1)|| SensorValue == (prevprevSensorValue - 1))
   {
      digitalWrite(13, LOW);   
}

        }


//delay(200);    

Serial.print("Sensor1: "); // print sensor output
Serial.println(sensor1); // print sensor output
Serial.print("Sensor2: "); // print sensor output
Serial.println(sensor2); // print sensor output
Serial.print("Sensor3: "); // print sensor output
Serial.println(sensor3); // print sensor output
Serial.print("SensorValue:            "); // print sensor output
Serial.println(SensorValue); // print sensor output

previous_Sensor_Millis = currentMillis;

prevSensorValue = SensorValue;
prevprevSensorValue = prevSensorValue;


  }

Although this thread is quite old I dug it out because I'm working on a similar project for my master thesis. I tried to get the code to work but no matter what I tried it didn't really work.

Before going into any detail I have a general question regarding my understanding of the code of the OP. As I see it the problem is that the LED already gets activated when the first sensor is touched and not just when a complete swipe is performed. Is that correct? But I'm a complete novice so I might also be wrong.

Thank you and best wishes
Chris