Resetting or zeroing the Millis at end of each cycle

Hi everyone, my code here is currently running but with issue.
The timing of my first two or three cycles is within parameters I need, but it slowly gets out of timing and the cycle then gets all over the place.
If there's some way I can zero out the Millis at the end of each cycle, or another fix, please let me know!
Thanks!

#include <LiquidCrystal_I2C.h>

// Pin definitions
const int relay1 = 53;  // Valve 4, Exhuast
const int relay2 = 51;  // Valve 3, Pressurize
const int relay3 = 49;  // Valve 2, Slide Movement
const int relay4 = 47;  // Valve 1, Chuck Movement
const int upLim = 52;   // define limit switch pin and name
const int relay5 = 45; //reset
// Global variables

int cycleCount = 0;
int Switchcount = 0;    //limit switch counter
int relay1state = LOW;
int relay2state = LOW;
int relay3state = LOW;
int relay4state = LOW;
int relay5state = LOW;
//time

unsigned long previousMillis1 = 0; 
unsigned long previousMillis2 = 0;
unsigned long previousMillis3 = 0;
unsigned long previousMillis4 = 0;
unsigned long previousMillis5 = 0;
unsigned long intervalOn1 = 4000;     
unsigned long intervalOff1 = 17000;    
unsigned long interval1 = 14000;  
unsigned long intervalOn2 = 3000;        
unsigned long intervalOff2 = 17000;       
unsigned long interval2 = 4000;         
unsigned long intervalOn3 = 3000;        
unsigned long intervalOff3 = 17000;      
unsigned long interval3 = 0;          
unsigned long intervalOn4 = 2000;        
unsigned long intervalOff4 = 8000;        
unsigned long interval4 = 0;     
unsigned long intervalOn5 = 1000;        
unsigned long intervalOff5 = 1000;        
unsigned long interval5 = 20000;        
int X = 0; 
LiquidCrystal_I2C lcd(0x27,20,4);


void setup() {

 lcd.init();
 lcd.clear();         
 lcd.backlight();      // Make sure backlight is on}

  pinMode(relay1, OUTPUT);
  digitalWrite(relay1, LOW);
  pinMode(relay2, OUTPUT);
  digitalWrite(relay2, LOW);
  pinMode(relay3, OUTPUT);
  digitalWrite(relay3, LOW);
  pinMode(relay4, OUTPUT);
  digitalWrite(relay4, LOW);
  pinMode(52, INPUT_PULLUP);  // defining pin 42 as an input for the upper limit switch. When this is closed the lift will lower
}

void loop() { 
if (cycleCount < 150000){

while(digitalRead(52) == HIGH) { // while the upper limit switch is not pressed

  lcd.setCursor(0,0);
  lcd.print("Cycle Test Running");
  lcd.setCursor(0,3);
  lcd.print("Switch Failure: ");
  lcd.setCursor(0,1);
  lcd.print("Cycle Count: ");
  lcd.setCursor(0,2);
  lcd.print("Pressure Failure: ");
  
unsigned long currentMillis5 = millis();
unsigned long currentMillis4 = millis();
unsigned long currentMillis3 = millis();
unsigned long currentMillis2 = millis();
unsigned long currentMillis1 = millis();

//Chuck movement
 if (currentMillis4 - previousMillis4 >= interval4) {
    previousMillis4 = currentMillis4;

    if (relay4state == LOW) {
      relay4state = HIGH;
      interval4 = intervalOn4;
    } else {
      relay4state = LOW;
      interval4 = intervalOff4;
    }
    digitalWrite(relay4, relay4state);
  }

  //Platform Movement
 if (currentMillis3 - previousMillis3 >= interval3) {
    previousMillis3 = currentMillis3;

    if (relay3state == LOW) {
      relay3state = HIGH;
      interval3 = intervalOn3;
    } else {
      relay3state = LOW;
      interval3 = intervalOff3;
    }
     digitalWrite(relay3, relay3state);
  }

  //Pressurize
 if (currentMillis2 - previousMillis2 >= interval2) {
    previousMillis2 = currentMillis2;

    if (relay2state == LOW) {
      relay2state = HIGH;
      interval2 = intervalOn3;
    } else {
      relay2state = LOW;
      interval2 = intervalOff2;
    }
    digitalWrite(relay2, relay2state);
  }


  //Exhuast
 if (currentMillis1 - previousMillis1 >= interval1) {
    previousMillis1 = currentMillis1;
    if (relay1state == LOW) {
      relay1state = HIGH;
      interval1 = intervalOn1;
    } else {
      relay1state = LOW;
      interval1 = intervalOff1;
    }
        digitalWrite(relay1, relay1state);
cycleCount ++;
lcd.setCursor(14,1);
lcd.print(cycleCount);
 }
if(digitalRead(52) == LOW) {
  Switchcount ++;
 lcd.setCursor(17,3);
 lcd.print(Switchcount);
}
}
}
if (cycleCount >150000) {
  lcd.setCursor(0,1);
  lcd.print("Cycle Test Finished!");
  exit(0);

}
}

Welcome to the forum

Why do you think that you need to zero the millis() value ? If you timing is "all over the place" then there is something wrong with your code

Thanks!
Although it likely is because of the timing being out of place, I’m not sure really how to fix it.
I’m still working on it though to see if I can fix with timing but I was curious if there’s a way to either exit and re-enter my loop or zero my time. This would cut me down a lot of math for the process if that’s even a possibility.

What is the sketch intended to do ?

The sketch is intended to open an air chuck, pushforward a platform that holds the air chuck, close the chuck over an air inlet, retract the platform, pressurize the system, and then open the chuck and exhaust the system.
Controlled by 4 relays (relay 5 was an error I should've taken it out of the code)

Make a copy of millis() in setup and use that as a base. If You need a reset, make that copy again.

That sounds like a Finite State Machine to me.

Rather than relying on timing to make each action happen in sequence why not complete each action then move on to the next one ?

I originally had the sketch drawn with delays in the process you're talking about. But I ran into an issue, which is that in case of a failure of the pressurizing, if the air chuck falls off prematurely, a limit switch will be knocked that sends me an error code. When using delays, the limit switch could only be activated outside of a delay. But with a time system, it can be activated anytime.

This probably won't work, because of int overflow (> ~32000).
int cycleCount = 0;
Make that unsigned long.
Leo..

I have a mechanical counter attached to the system too, but I will implement that into my code. Thanks!

A FiniteStateMAchine does not depend on delay(). In fact, if you do use delay() then an FSM will not work

Your FSM could have these states

open air chuck, 
push platform forward
close the chuck over an air inlet
retract the platform
pressurize the system
open the chuck
exhaust the system.

Each state has the code to do the necessary action and when that action is complete the sketch moves on to the next state

A very convenient way to do this is to use an enum to name the states and switch/case to move between the states so that only the code for the current case is executed

A state ends when its actions are complete, perhaps triggered by a switch, or when the required time has passed. Timing is done using millis(). If a fault is detected then the sketch can move to a fault state which halts the process or perhaps takes remedial action such as restarting the system

Whilst looking to do this relay sequenced on a different way, I wonder about the copy/paste/edit code for //Pressurize. It's part of the problem with C/P/E development - is it the same? Am I sure? Is it a bit different? Why? Is that a typo there, a missed edit?


Can you confirm this pattern of operation? I left Relay5 in there for fun. Time in seconds to save wear on my '0' key:
Relay 1:  14 hold off, cycle 4 on 17 off
Relay 2:   4 hold off, cycle 3 on 17 off
Relay 3:          just cycle 3 on 17 off
Relay 4:          just cycle 2 on  8 off
Relay 5: 20 hold off,  cycle 1 on  1 off

The time for the relays to finish their hold off period and do one cycle of on/off

Relay 1:       35
Relay 2:       24
Relay 3:       20
Relay 4:       10
Relay 5:       22

At 35 seconds, relay 1 will have been held off, turned on and then off once. Do you meant that during that time any other relays will perhaps have switched on and off a few times as certainly would Relay 5? Seven times or so?

Or do you meant that everyone should chill and at the 35 seconds mark, the entire process restarts at the beginning, that is to be clear to say starting at the very beginning with the hold off periods?

My idea is just to have a table with 35 entries each entry of which would say which relays are on and which are off. Coding that would vary with personal anbilities, styles and preferences, but it would be straight ahead in any case and very easily seen to be correct or modified should the need arise.

It would lock you into a 1 second resolution.

a7

I used the time I am waiting for she who must never be kept waiting (definition of irony) to text and say we are off to the beach to code this demo of a dumb sequencer.

I used 333 millisecond steps as 1000 is an eternity during testing.

Play with it here:

Wokwi_badge Umbrella Academy Dumb Relay Sequencer


// https://forum.arduino.cc/t/resetting-or-zeroing-the-millis-at-end-of-each-cycle/1221287
// https://wokwi.com/projects/389172935034378241

// Pin definitions
const int relay1 = 53;  // Valve 4, Exhuast
const int relay2 = 51;  // Valve 3, Pressurize
const int relay3 = 49;  // Valve 2, Slide Movement
const int relay4 = 47;  // Valve 1, Chuck Movement
const int relay5 = 45;  // Valve 1, Chuck Movement

byte relayPin[] = {relay1, relay2, relay3, relay4, relay5};

byte NRELAYS = sizeof relayPin / sizeof *relayPin;

unsigned long aTimer;
unsigned long now;         // always millis() for the entire loop
const int INTERVAL = 333;  // step duration 

const byte R1 = 1;
const byte R2 = 2;
const byte R3 = 4;
const byte R4 = 8;
const byte R5 = 16;

byte relayBit[] = {R1, R2, R3, R4, R5};

byte sequence[] = {
  0,
  0,
  0,
  R1,
  R1 + R3,
  R1 + R3 + R5,
  R2 + R4,
  R1 + R3 + R5,
  R2 + R4,
  R1 + R3 + R5,
  R2 + R4,
  R1 + R3 + R5,
  R3 + R5,
  R5, 
  0,
  0,
  0,
  R1 + R2 + R4 + R5,
  R3,
  R1 + R2 + R4 + R5,
  R3,
  R1 + R2 + R4 + R5,
  R3,
  R1 + R2 + R4 + R5,
  0,
  0,
};

const int sequenceLength = sizeof sequence / sizeof *sequence;

void setup() {
  Serial.begin(115200);
  Serial.println("UA Sequencer V.0\n");

  for (int ii = 0; ii < NRELAYS; ii++) {
    pinMode(relayPin[ii], OUTPUT);
    digitalWrite(relayPin[ii], LOW);
  }
}

void loop() { 
  static unsigned long lastTime;
  static int step;

  now = millis();

  if (now - lastTime < INTERVAL) return;    // not time to do anything

  lastTime = now;

  for (int ii = 0; ii < NRELAYS; ii++) {
    if (sequence[step] & relayBit[ii])
      digitalWrite(relayPin[ii], HIGH);
    else
      digitalWrite(relayPin[ii], LOW);
  }

  step++;
  if (step >= sequenceLength) step = 0;   // rinse and repeat
}

Just for fun, yes this passes for fun in my empty life.

a7

My bit of fun is as follows

enum states
{
    RELAY0,
    RELAY1,
    RELAY2
};
byte currentState = RELAY0;
unsigned long stateStartTime;
unsigned long currentTime;
int currentPeriod = 1000;
const byte buttonPin = A3;

void setup()
{
    Serial.begin(115200);
    pinMode(buttonPin, INPUT_PULLUP);
    printCurrent(currentState, "button is pressed");
}

void loop()
{
    currentTime = millis();
    switch (currentState)
    {
        case RELAY0:
            if (digitalRead(buttonPin) == LOW)
            {
                currentState = RELAY1;
                currentPeriod = 2000;
                stateStartTime = currentTime;
                printCurrent(currentState, currentPeriod);
            }
            break;
        case RELAY1:
            if (currentTime - stateStartTime >= currentPeriod)
            {
                currentState = RELAY2;
                currentPeriod = 1000;
                stateStartTime = currentTime;
                printCurrent(currentState, currentPeriod);
            }
            break;
        case RELAY2:
            if (currentTime - stateStartTime >= currentPeriod)
            {
                currentState = RELAY0;
                currentPeriod = 3000;
                stateStartTime = currentTime;
                printCurrent(currentState, "button is pressed");
            }
            break;
    }
}

void printCurrent(byte state, int period)
{
    Serial.print("in state ");
    Serial.print(state);
    Serial.print(" for ");
    Serial.println(period);
}

void printCurrent(byte state, char* message)
{
    Serial.print("in state ");
    Serial.print(state);
    Serial.println(" waiting for button press");
}

I threw it into the wokwi simulator and fixed changed a few things. At least I think you meant to print the message in one of the printCurrent() functions; the only message that made sense was "waiting for button".


Wokwi_badge @UKHeliBob Relay Thing


a7

1 Like

You are right. Having allowed for a string to be passed to the printCurrent() function the sketch never actually made use of it

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.