Questions on Timing and Time Interval Changes based on Force Sensor Response

Ardruino Uno
4 FlexiForce 1lb force sensors
piezo buzzer

We are trying to use the materials listed above to recognize when at least one of force sensors is saturated. Once one of the force sensors is saturated, we would like to time how long the force is at this level. Once the saturation time reaches 15 minutes, the piezo buzzer will go off. Once there is no force (or minimal force) on the sensors, a timer will start and time the amount of time there is little to no force.

When one of force sensors becomes saturated again, the time that was recorded when there was no force will be used in a ratio to set the new amount of time before the buzzer goes off again. This cycle will repeat indefinitely.

The FlexiForce sensors work like resistors, the more force then feel, the less resistance they exhibit.

Right now we have our Arduino set up so that when the FlexiForce sensor reaches a certain voltage, it will set the piezo buzzer off and an LED turns on. If the force is below this set amount (voltage) then the buzzer and LED remain off.

We need help understanding what type of timing mechanism and coding we should use for this application. If you have any suggestions at all, we are looking for ideas to work with, this is our first time using an Arduino board, and none of us have experience coding, so all the help you can give would be greatly appreciated! Thanks!

I forgot, here is our code we have to do the function we have right now.

unsigned long time;

void setup() {
   // Start serial at 9600 baud
    Serial.begin(9600); 
    pinMode(13, OUTPUT);
    pinMode(9, OUTPUT);
}

void loop() {

  int sensorValue = analogRead(A0);        // Read the input on analog pin 0:
  
  float voltage = sensorValue * (5.0 / 1023.0);       // Convert the analog reading (which goes from 0 - 1023) to a voltage (0 - 5V):
  float pressuretime = millis();
  Serial.println(voltage);       // Print out the value you read:
  int voltageValue = 3.5;      // Turn on light if voltage value is greater than 3.5V
  
  
  if (voltage > voltageValue) {
      Serial.print("HIGH PRESSURE                 ");
      digitalWrite(13, HIGH);
      digitalWrite(9, 125);      // Almost any value can be used except 0 and 255
      int alerttime;
      alerttime = 6000;
      delay(alerttime);          // wait for a delayms ms

     delay(100);          // wait for a delayms ms   
}   

  if (voltage < voltageValue) {
    digitalWrite(13, LOW);
    digitalWrite(9, 0); 
    Serial.print("Time: ");
    time= millis();
}
  
  int time=100;         // Wait 100 milliseconds
  delay(time);
}

This is how you record the time:

unsigned long someTime = millis();

This is how you check how long it has been since that recorded time:

unsigned long elapsed = millis() - someTime;

From your logic, you simply need your "someTime" variable to be "lastTimeWhenUnSaturatedWasRead" which is done with a simple if statement. Independently of the aforementioned if statement, you need to check when elapsed has reached the threshold. Again, this is also done with a simple if statement. So the psuedo code would look like this:

if (input is unsaturated)
  set lastTimeWhenUnSaturatedWasRead to now

if (elapsed time since last unsaturated is greater than threshold)
  do something about it

Thank you for your help, it has greatly helped us to move forward. We are now having a problem that the buzzer is correct the first time the voltage is >= saturation, but then the buzzer just continues to go off without waiting anytime. How do we get the elapsed time to reset for each time when the voltages is <saturation?

// Flexiforce quick start example
// Reads A0 every 100ms and sends voltage value over serial
unsigned long time;

void setup() 
{
  // Start serial at 9600 baud
  Serial.begin(9600); 
  pinMode(13, OUTPUT);
  pinMode(9, OUTPUT);
  unsigned long time=millis();

  // Read the input on analog pin 0:
  
  
  // Convert the analog reading (which goes from 0 - 1023) to a voltage (0 - 5V):

  
  
  
  
  
  // Print out the value you read:
 
 
  // Turn on light if voltage value is greater than 3.5V
 
}



    void loop() 
{
  int sensorValue = analogRead(A0);
  float voltage = sensorValue * (5.0 / 1023.0); 
  Serial.println(voltage);
  int voltageValue = 2.0;
  int upTime;
  int elapsed;
  int sitTime=3000;
  
  
  if (voltage > voltageValue) {
    
    unsigned long elapsed= millis();
    
    digitalWrite(13,LOW);
    Serial.print("HIGH PRESSURE                 ");
   if (elapsed>=sitTime){
   digitalWrite(9, 125); 
    }
  }
  
  
  if (voltage < voltageValue){
    unsigned long upTime = millis();
    Serial.print("LOW PRESSURE      ");
    digitalWrite(13,HIGH);
    digitalWrite(9,0);
    unsigned long elapsed=0;
  } 
}

DetroitTitan13:
Thank you for your help, it has greatly helped us to move forward. We are now having a problem that the buzzer is correct the first time the voltage is >= saturation, but then the buzzer just continues to go off without waiting anytime. How do we get the elapsed time to reset for each time when the voltages is <saturation?

Well first, let's clean up the code. Start by putting each curly brace on its own line and using the Auto Format Tool (Under Tools > Auto Format in the Arduino IDE).

  // Start serial at 9600 baud
  Serial.begin(9600);

The comment doesn't tell us much here.

  pinMode(13, OUTPUT);
  pinMode(9, OUTPUT);

If you're not going to tell us what these pins do via comments, you should be using descriptive const. This will also make it easier down the road to change pins:

In the Global Scope:

const int ledDisplayPin = 13;
const int someUnkownPin = 9;

and then in the setup:

  pinMode(ledDisplayPin , OUTPUT);
  pinMode(someUnkownPin , OUTPUT);

Then anywhere in your code where you do something with pins 13 or 9 (like digitalWrite()) use the named constants instead.

unsigned long time=millis();

This goes out of scope as soon as setup is finished, so it's useless

  // Read the input on analog pin 0:
  
  
  // Convert the analog reading (which goes from 0 - 1023) to a voltage (0 - 5V):

  
  
  
  
  
  // Print out the value you read:
 
 
  // Turn on light if voltage value is greater than 3.5V

Way too much white space and pointless comments. When you're asking people for help with your code, it's best to get rid of stuff like this.

  float voltage = sensorValue * (5.0 / 1023.0); 
  Serial.println(voltage);
  int voltageValue = 2.0;
  ...
  if (voltage > voltageValue) {

The Arduino doesn't have a floating point unit, so any floating point calculations are fairly taxing on the new system. This is an example of where floating point calculations can be substituted with a couple simple arithmetic calculations before hand. Since you are assuming 5V = 1023 reading, you can multiple 1023 by 5/2 which gives you a result of 409. That means that you can simple do this:

int sensorValue = analogRead(A0);
if (sensorValue > 409)
...

In addition, in line 3, you are trying to assign a floating point value to an int. It may not affect the functionality, but it's confusing and unnecessary.

unsigned long elapsed= millis();
...
if (elapsed>=sitTime){

millis() tells you how long the Arduino has been running for. You don't want to compare the Arduino's runtime, you want to compare and elapsed time. In addition, once the if statement is over, elapsed goes out of scope, so it can't be used by any other part of the program.

digitalWrite(9, 125);

digitalWrite accepts the pin number and either HIGH or LOW. While 125 won't break it, it's again, confusing and unnecessary. Since I have no idea what this mystery pin is used for, I can't tell if you're trying to do with it. You might need analogWrite(), but that's just a shot in the dark.

  if (voltage < voltageValue){
    unsigned long upTime = millis();

Again, upTime goes out of scope as soon as the if statement ends, so this is doing nothing.

I recommend scrapping the majority of your code and starting over with the psuedo code that I posted.

Arrch,

Thank you for the help. We have cleaned up the code as you had recommended, and added some descriptions.

As you stated, "millis() tells you how long the Arduino has been running for. You don't want to compare the Arduino's runtime, you want to compare and elapsed time. In addition, once the if statement is over, elapsed goes out of scope, so it can't be used by any other part of the program."

Does this mean that in order to keep track of the amount of time that there is no force sensed, we need to use something other than millis()?
We want to capture the upTime, multiple it by a number, and then use this value as the new sitTime in the line below. What function should we use to track upTime if not millis()?

if ((unsigned long)(millis()-elapsedTime)>=sitTime)
void setup() 
{
  Serial.begin(9600); 
  pinMode(13, OUTPUT); // Turns LED on when no pressure
  pinMode(9, OUTPUT);  // Piezo Buzzer
  unsigned long elapsedTime=millis();
}

void loop() 
{
  int sensorValue = analogRead(A0);
  int voltage = sensorValue * (5.0 / 1023.0);   // Convert the analog reading (which goes from 0 - 1023) to a voltage (0 - 5V):
  Serial.println(voltage);
  int voltageValue = 2.0;
  int upTime;
  int elapsedTime;
  int sitTime=3000;

  if (voltage > voltageValue) {
    digitalWrite(13,LOW);                    // Turns LED off
    Serial.print("HIGH PRESSURE                 ");
    if ((unsigned long)(millis()-elapsedTime)>=sitTime){
      digitalWrite(9, HIGH);                  // Turns on Buzzer
      elapsedTime=elapsedTime+sitTime;
    }
  }

  if (voltage < voltageValue){         // This section is for when the person is out of the chair
    unsigned long upTime = millis();   // We want to capture the amount of time that the person is out of the chair, and use that time to calculate the new amount of time untill the buzzer goes off when they are in their seat.
    Serial.print("LOW PRESSURE      ");
    digitalWrite(13,HIGH);  // Turns LED on
    digitalWrite(9,0);      // Turns Buzzer off
  } 

}

You are still making mistakes with variable scope. Read this: Variable Scope in C++

So I completely scratched my code and when back to my mapping. This is my new code, and I have tried to use a one second delay and and a counter (t++) to keep track of my time while my voltage tests are running. This code checks out in the compiler, but when I upload it to my arduino with a piezo buzzer and pressure sensor connected I am not getting any actions, such as the piezo buzzer going off or anything. What is causing this system not to work???

void setup() 
{
  Serial.begin(9600); 
  pinMode(9, OUTPUT);  // Piezo Buzzer
}
void loop ()
{
  int counter = 0;  
Reset:
  int sensorValue = analogRead(A0);        		// reads value from force sensor located in A0 
  int voltage = sensorValue * (5.0 / 1023.0);  		 // Convert the analog reading (which goes from 0 - 1023) to a voltage (0 - 5V):
  int voltageValue = 2.0;      				 // sets the pressure limit, so that when pressure is higher than this value considered "high pressure" sets threshold for high and low 
  int Tup=30000;                  // Initial Tup is 30 sec
  int Tdown=900000;              // Initial Tdown is 15 min (900 sec)
  int Action;             // When action == 1 carry out the do loop
  int t=0;                // Time counter

  if (voltage >= voltageValue) {
    Action=1;
    Serial.println(voltage);      				// print out voltage
    do{
beginning:
      delay (1000);        // start Timing (t);
      if ((voltage> voltageValue) && (t > Tdown)) 	// has been sitting for 15 minutes
      {
        digitalWrite(9,HIGH); 			// Buzzer goes off for 3 seconds;
        delay (3000);
        digitalWrite(9,LOW); 
        if (voltage > voltageValue){
          counter++;			// Count missed times
          Action = 0;
          goto Reset;			// Reset
        }
        goto Relief;                     // Relief function
      }
      else if ((voltage<voltageValue) && (t < Tdown))  	// has gotten up before 15 minutes is up 
      { 
        Tup = t / 30;                // changes Tup value for next test in Relief function
        t = 0;
        goto Relief;                        // Relief function
      }
      t++;                          // time counter increases by 1
    }  
    while(Action=1);
Relief: 
    while (voltage<voltageValue){
      delay (1000);                  // start Timing (t);
      if ((voltage < voltageValue) && (t > Tup))  	// has been up for more than 30 seconds
      {
        t = 0;                   // resets time counter
        Action = 0;              // will not return to do loop
        goto Reset;   		// Reset
      }
      else if ((voltage > voltageValue) && (t < Tup))  	// has sat down before 30 seconds
      {
        Tdown = t * 30;              	 // changes up time to new value
        t = 0;                          // resets time counter
        goto beginning ;		 //goes to 'beginning' of do loop
      }  
      t++;                        // increase time counter by 1
    }
  }
}

Ditch your gotos; you're not going to get much help from other people when you use them

    while(Action=1);

Infinite loop, doubt that is your intention?

We do want this to be an infinite loop. What can we use instead of go to's? Should I just make each of those sections functions? Thanks for the help.

DetroitTitan13:
We do want this to be an infinite loop.

Then why complicate it with a variable? Why not simplify it?

while(1); // infinite loop, once we reach this point, nothing happens until reset

What can we use instead of go to's? Should I just make each of those sections functions? Thanks for the help.

It isn't as simple as just putting something in place of it. You have to rethink your code structure. Functions can help, but you have to understand that they return to the same place when they are done running, so you have to account for that in your structure.