help with timers- if value outside a range for set amount of time do > something

Yeah this will be wired to car ignition so if it is left on long enough to roll over back to zero I would be thinking the car won't start from a flat battery haha.

I have a pretty elaborate way if writing min and max values to eeprom due to the arrays but I defined a second array naming the slots for the values in eeprom and then used the wheels naming to write to the eeprom slot. May not be the best way but it works I'll post that section when i get home see if you have any thoughts
But I guess if it isn't broken don't fix it to some extent right? Haha

Not sure if there is a better way to do this but this is how i wrote to eeprom on calibration:

Here is just sections so its not so hard to find. The reason i used the array also when naming the sensor min array is just so its full proof to those slots on the eeprom 1,11,21,31 and so on otherwise if i had a number wrong there (or change it later) id have to update it manually

// Naming some variables
// Height sensors ( values, Pins, Min values, and Max values)
    const int SensorMinSlot[4] = { 1, 11, 21, 31};
    const int SensorMaxSlot[4] = { 2, 12, 22, 32};
    const int HeightSensorPin[4] = { A0, A1, A2, A3 };
    int HeightSensorValue[4];  
    int SensorMin[4] = { EEPROM.read(SensorMinSlot[0]), EEPROM.read(SensorMinSlot[1]), EEPROM.read(SensorMinSlot[2]), EEPROM.read(SensorMinSlot[3])};
    int SensorMax[4] = { EEPROM.read(SensorMaxSlot[0]), EEPROM.read(SensorMaxSlot[1]), EEPROM.read(SensorMaxSlot[2]), EEPROM.read(SensorMaxSlot[3])};
    int SensorRange[4] = { (SensorMax[0] - SensorMin[0]), (SensorMax[1] - SensorMin[1]), (SensorMax[2] - SensorMin[2]), (SensorMax[3] - SensorMin[3]) };

Then when calibration is on ( set to true when a pin is low during setup only) it does some auto airing out and inflating the car to get to certain heights then saves these values to eeprom as new max and min values

for(int Wheels = 0; Wheels < 4; Wheels++){
                    HeightSensorValue[Wheels] = analogRead(HeightSensorPin[Wheels])/4;                    
                    EEPROM.write(SensorMaxSlot[Wheels],HeightSensorValue[Wheels]);
                    Serial.print(EEPROM.read(SensorMaxSlot[Wheels]));
                    Serial.print(" ");
                }  // end for

I will be tightening things up as right now i have multiple for loops in the calibration but its working flawlessly at the moment so pretty happy with it. Heres the full calibration code if wanting to have a look anyway

// Calibration Start   
            if (Calibration==0){
                
                    Serial.println("Calibrating Initiated Please Wait");
            
                // Flash Built in LED
                    digitalWrite(LED_BUILTIN, 1);
                    delay(1000);
                    digitalWrite(LED_BUILTIN, 0);
                    delay(1000);
                    digitalWrite(LED_BUILTIN, 1);
                    delay(2000);
                    digitalWrite(LED_BUILTIN, 0);
                
                // Calibrate Min Sensor Values
                    Serial.println("Airing out Please Wait");               
                    for(int Wheels = 0; Wheels < 4; Wheels++){
                    digitalWrite (DeflateRelays[Wheels], 1);    
                    }  // end for
                    delay(10000);
                    for(int Wheels = 0; Wheels < 4; Wheels++){
                    digitalWrite (DeflateRelays[Wheels], 0);
                    }  // end for                   
                    Serial.println("Saving Minimum Sensor Values to EEPROM");
                    for(int Wheels = 0; Wheels < 4; Wheels++){
                    HeightSensorValue[Wheels] = analogRead(HeightSensorPin[Wheels])/4;                    
                    EEPROM.write(SensorMinSlot[Wheels],HeightSensorValue[Wheels]);
                    Serial.print(EEPROM.read(SensorMinSlot[Wheels]));
                    Serial.print(" ");
                    }  // end for
                    Serial.println(" Minimum Sensor Values stored:");
                
                // Calibrate Max Sensor Values             
                    Serial.println("Inflating Please Wait");               
                    for(int Wheels = 0; Wheels < 4; Wheels++){
                    digitalWrite (InflateRelays[Wheels], 1);    
                    }  // end for
                    delay(10000);              
                    for(int Wheels = 0; Wheels < 4; Wheels++){
                    digitalWrite (InflateRelays[Wheels], 0);
                    }  // end for                  
                    Serial.println("Saving Minimum Sensor Values to EEPROM");
                    for(int Wheels = 0; Wheels < 4; Wheels++){
                    HeightSensorValue[Wheels] = analogRead(HeightSensorPin[Wheels])/4;                    
                    EEPROM.write(SensorMaxSlot[Wheels],HeightSensorValue[Wheels]);
                    Serial.print(EEPROM.read(SensorMaxSlot[Wheels]));
                    Serial.print(" ");
                }  // end for
                Serial.println(" Maximum Sensor Values stored:");                    
            } // End Calibration if

So i uploaded my code and it works perfect for the first maybe 20 seconds after that it autolevels with no delay i output some serial and current time is running fine but the lasttime stable is becoming a negative number so therefore current time - last time is always going to be larger than the allowed delay time so allowing for autolevel instantly rather than the 5 second delay.

Any ideas why?

Please note i only have 2 as wheels value because i only have a 4 channel relay board and 2 sensors hooked up at the moment for testing

// Loop Begin    
    void loop() {

     CurrentTime=millis();
     
      // start reading sensor values
                for(int Wheels = 0; Wheels < 2; Wheels++){
                    HeightSensorValue[Wheels] = analogRead(HeightSensorPin[Wheels])/4;
                    
                    // Sensor Low
                    if( HeightSensorValue[Wheels] < (TargetHeight[Wheels]-(SensorRange[Wheels]/Accuracy))){
                      SensorLow[Wheels] = true;
                      SensorHigh[Wheels] = false;
                      SensorStable[Wheels] = false;                                         
                    }

                    // Sensor High
                    if( HeightSensorValue[Wheels] > (TargetHeight[Wheels]+(SensorRange[Wheels]/Accuracy))){
                      SensorLow[Wheels] = false;
                      SensorHigh[Wheels] = true;
                      SensorStable[Wheels] = false;                                         
                    }

                    // Sensor Stable
                    if( HeightSensorValue[Wheels] >= (TargetHeight[Wheels]-(SensorRange[Wheels]/Accuracy)) && HeightSensorValue[Wheels] <= (TargetHeight[Wheels]+(SensorRange[Wheels]/Accuracy))){
                      SensorLow[Wheels] = false;
                      SensorHigh[Wheels] = false;
                      SensorStable[Wheels] = true;                                          
                    }                    



                   // Autolevel Procedure
                  if(SensorStable[Wheels]){
                    LastTimeStable[Wheels]= CurrentTime; 
                    digitalWrite(InflateRelays[Wheels], 0);
                    digitalWrite(DeflateRelays[Wheels], 0);                  
                  }

                  if(SensorLow[Wheels] && (CurrentTime - LastTimeStable[Wheels]>= DelayTime)){
                    digitalWrite(InflateRelays[Wheels], 1);
                    digitalWrite(DeflateRelays[Wheels], 0);                   
                  }

                  if(SensorHigh[Wheels] && (CurrentTime - LastTimeStable[Wheels]>= DelayTime)){
                    digitalWrite(InflateRelays[Wheels], 0);
                    digitalWrite(DeflateRelays[Wheels], 1);                   
                  }

                  Serial.println("LastTimeStable: ");
                  Serial.print(Wheels);
                  Serial.print(" ");
                  Serial.println(LastTimeStable[Wheels]);



                  
                }  // end for
                
      //AutolevelCode
                
Serial.println(CurrentTime);
        
    }// End Loop

Here's the output from the serial both sensors at rest not moving and stable but randomly lasttime1 was stable jumps to a negative number

LastTimeStable 0: 32138
LastTimeStable 1: 32209
CurrentTime:32209
LastTimeStable 0: 32138
LastTimeStable 1: 32281
CurrentTime:32281
LastTimeStable 0: 32138
LastTimeStable 1: 32353
CurrentTime:32353
LastTimeStable 0: 32138
LastTimeStable 1: 32424
CurrentTime:32424
LastTimeStable 0: 32138
LastTimeStable 1: 32496
CurrentTime:32496
LastTimeStable 0: 32138
LastTimeStable 1: 32568
CurrentTime:32568
LastTimeStable 0: 32138
LastTimeStable 1: 32640
CurrentTime:32640
LastTimeStable 0: 32138
LastTimeStable 1: 32711
CurrentTime:32711
LastTimeStable 0: 32138
LastTimeStable 1: -32753
CurrentTime:32783
LastTimeStable 0: 32138
LastTimeStable 1: -32680
CurrentTime:32856
LastTimeStable 0: 32138
LastTimeStable 1: -32607
CurrentTime:32929
LastTimeStable 0: 32138
LastTimeStable 1: -32534
CurrentTime:33002
LastTimeStable 0: 32138
LastTimeStable 1: -32461
CurrentTime:33075
LastTimeStable 0: 32138
LastTimeStable 1: -32389
CurrentTime:33147
LastTimeStable 0: 32138
LastTimeStable 1: -32316
CurrentTime:33220
LastTimeStable 0: 32138
LastTimeStable 1: -32243
CurrentTime:33293

And further down after a few more seconds both become negative

LastTimeStable 0: 32138
LastTimeStable 1: -32170
CurrentTime:33366
LastTimeStable 0: 32138
LastTimeStable 1: -32098
CurrentTime:33438
LastTimeStable 0: 32138
LastTimeStable 1: -32025
CurrentTime:33511
LastTimeStable 0: 32138
LastTimeStable 1: -31952
CurrentTime:33584
LastTimeStable 0: -31880
LastTimeStable 1: -31880
CurrentTime:33656
LastTimeStable 0: -31880
LastTimeStable 1: -31805
CurrentTime:33731
LastTimeStable 0: -31880
LastTimeStable 1: -31731
CurrentTime:33805
LastTimeStable 0: -31880
LastTimeStable 1: -31657
CurrentTime:33879
LastTimeStable 0: -31880
LastTimeStable 1: -31584
CurrentTime:33952
LastTimeStable 0: -31880
LastTimeStable 1: -31510
CurrentTime:34026
LastTimeStable 0: -31880
LastTimeStable 1: -31436
CurrentTime:34100
LastTimeStable 0: -31363
LastTimeStable 1: -31363
CurrentTime:34173
LastTimeStable 0: -31363
LastTimeStable 1: -31289
CurrentTime:34247
LastTimeStable 0: -31363
LastTimeStable 1: -31215
CurrentTime:34321
LastTimeStable 0: -31363
LastTimeStable 1: -31140
CurrentTime:34396
LastTimeStable 0: -31363
LastTimeStable 1: -31067
CurrentTime:34469
LastTimeStable 0: -31363
LastTimeStable 1: -30993
CurrentTime:34543
LastTimeStable 0: -31363
LastTimeStable 1: -30919
CurrentTime:34617
LastTimeStable 0: -30845
LastTimeStable 1: -30845
CurrentTime:34691
LastTimeStable 0: -30845
LastTimeStable 1: -30772
CurrentTime:34764
LastTimeStable 0: -30845
LastTimeStable 1: -30698
CurrentTime:34838
LastTimeStable 0: -30845
LastTimeStable 1: -30624
CurrentTime:34912
LastTimeStable 0: -30845
LastTimeStable 1: -30551
CurrentTime:34985

Think i solved it LastTimeStable was set as an Int so i assigned it as an Unsigned Long and no longer returns a negative after 30 seconds

darcy_d:
Think i solved it LastTimeStable was set as an Int so i assigned it as an Unsigned Long and no longer returns a negative after 30 seconds

Well diagnosed. 32767 is the highest positive value that int can hold. After that it cycles round to -32768 which is the most negative value for int. On a desktop program, you might get a "integer/arithmetic overflow" error. But there are no such luxuries on Arduino.

Any variable used to store a time or compare with a time from millis() should be unsigned long, which is 32 bits long vs. 16 bits for int. (At least for Atmega MCUs, which have 8-bit architecture, anyway. Suspect int and long are both 32 bits in esp8266, and other more modern MCUs).

Yeah I thought I had it as an unsigned long bit went back through and saw it wasn't. When I printed the serial and saw it around the 32000 mark that's when I started thinking it just be defined wrong.

Any ideas on making the calibration neater or is the second array defining the eeprom slot a good idea?

darcy_d:
Any ideas on making the calibration neater or is the second array defining the eeprom slot a good idea?

It does seem over complicated, having to use arrays to hold the eeprom locations. I'm not sure why you are using the particular locations shown in the code. If the code to write the data and the code to read the data were structured in the same way, you could just use an int variable to hold the index of the next eeprom location to be written, and just increment it (++) after each read/write.

PaulRB:
It does seem over complicated, having to use arrays to hold the eeprom locations. I'm not sure why you are using the particular locations shown in the code. If the code to write the data and the code to read the data were structured in the same way, you could just use an int variable to hold the index of the next eeprom location to be written, and just increment it (++) after each read/write.

The only reason I chose those values was that it's easy for me to see what each one was and remain consistent

As an example.
For corner 0 (front left throughout all code) We have 01 being min value 02 being max 03 user height 1, 04 user height 2, 05 user height 3 and so on then if I want front right it's the same but 11, 12, 13, 14 etc so the first digit represents the corner and second represents what it is 1 min 2 max 3 user1 and so on

I could have done it all in another array and had 0-3 being min 4-7 max and kept going but I thought if I had a system like that if remember better.

Probably isnt a simpler way to value them in the same orser i have but It works anyway so I'll probably leave it for now

I've ran into an issue well not an issue but I want to debug and make this a little safer

Overview of how it works so far

The sensors are rotary pots connected to arms that attach to chassis and moving suspension arms so as the car is lowered the pot moves clockwise as the car is raised the pot moves counterclockwise.

The program reads the sensor positions and if they are inside a set range it updates the last time each corner was stable to the current time.

When they fall below or above this range the program checks if they are outside the range and compares it with a time value (30 seconds) if after 30 seconds they are still outside the range it inflates or deflates that corner until that sensor is back stable again and repeats over and over.

The Issue
My concern is if a wire is broken the car will inflate or drop on that 1 corner and continue to do so even if the sensor isnt responding.

This leads me to my question:
I have a couple of ideas but im not sure how to go about it

First idea is to have an array containing the amount of time each valve has been on for and if it exceeds a set time say 1 second and the sensor hasnt changed value then throw a code (Serial print) and disable that corner from autolevelling ( this could have its own issues due to noise so if a sensor wire is actually broken the sensor value will change anyway due to noise and interference unless i put an extra pulldown resistor or something?)

Second idea (not sure if possible) is to essentially see if the sensor is incrementing correctly basically if the new sensor value is +1 or -1 from the last sensor value it is working correctly. If for any reason it breaks or is disconnected then the sensor value will go from say 122 to maybe 244 or 1 or etc meaning it didnt move to that position fluently it was suddenly changed. this would have to have some tolerence im guessing but pretty sure the arduino can process this faster than the sensor can move maybe?

3rd idea is to add pressure sensors as well as height sensors so if the pressure changes and the height doesnt then something is wrong and vice versa. ( i will probably do this as well but this also ahs its own issues and id rather just work of sensors)

Any ideas are appreciated or ways to try and code this?

You could record the time at which each pump is switched on. Then use this as a timeout. If the pump has been running for, say, 1 minute, and the sensor has not returned to the correct range, then something is wrong. At that point your code should indicate the error somehow and switch off the pump.

PaulRB:
You could record the time at which each pump is switched on. Then use this as a timeout. If the pump has been running for, say, 1 minute, and the sensor has not returned to the correct range, then something is wrong. At that point your code should indicate the error somehow and switch off the pump.

Yeah that's essentially what I was thinking although would have to be within a few seconds not a minute due to having a tank on board at 200 psi so the full range of motion from inflated max to aired out takes a few seconds. Can I put a pull down resistor in parallel with the 10k pot on the analog input? Say a 100k resistor so when the pot wire is disconnected the analog input goes to ground so that way any small magnetic interference or noise shouldn't make the analog signal change and should show 0? Is that doable?

Yes, I think that should work. It will mean that the readings from your pots will change, and no longer be quite linear, but I don't think that will matter too much.

PaulRB:
Yes, I think that should work. It will mean that the readings from your pots will change, and no longer be quite linear, but I don't think that will matter too much.

It all calibrates itself anyway during calibration mode so it bases its calculations off the min and max values obtained through the pot when aired out and inflated and if its not 100% linear it doesnt matter ill just tighten the accuracy up as needed.

something larger as the pull down would be better wouldnt it? Better as in less of an impact on the values of the pot?

Say 100k resistor as pulldown compared to something closer like 20k which would be a much closer voltage divider.

Yes. You are right to say that a higher value will increase the possibility of noise affecting the analog input, should the wire to the pot break. If you used 2M that would be much more of a problem. But with 200K I think it will be ok.