Finite State Machine coding

I'm going to jump right in and be detailed as possible:

Project components:

Funduino uno R3

12V power supply 5A

AQMH3615NS switching relay board with PWM

limit switch (using NO and C connections)

12V linear actuator with a 10% duty cycle

Here's what I want to accomplish as a FSM:

(state 1) NO movement

(state 2) linear actuator move down at set speed for desired time

(state 3) timer - interruptable (I'm learning blinkwithoutdelay example still here)

(state 4) linear actuator move up at set speed for desired time

To make it slightly more complex, I am programming a limit switch to change certain states or the absence of the trigger as well over a certain time.

Pics: Overview of Setup, relay wiring setupArduino wiring setup

NOTE: I moved the limit switch wire from A0 to 12 and am using the internal pullup resistor on the board - which was harder info the learn about than imagined.

Arduino ports used:

inputs:

5v: 5v output from relay (green wire)

12: NO limit switch to GND (purple)

outputs:

3: PWM control for relay

7:IN1 on switching relay (white)

8:IN2 on switching relay (blue)

GND: Ground output to relay and limit switch (black)

Relay wiring:

block1

9-36V: power from power supply (red)

PGND: Ground from power supply (black)

block 2

out1: switching 2 wire DC motor (red)

out2: Switching 2 wire DC motor (black)

Orange block

com: GND output from Arduino (black)

in2: output from arduino#8 (blue)

in1: output from arduino#7 (white)

PWM: output from Arduino#3 (red)

5V0: output TO Arduino 5V IN(blue)

#define pwm 3
#define in1 7
#define in2 8
const int delaya = 800;
const int delayT = 230000;
const int delayup = 4000;
const int delaydown = 7000;
unsigned long chrono = millis();
// constants won't change. They're used here to set pin numbers:
const int buttonPin = 12;     // the number of the pushbutton pin
const int ledPin =  13;      // the number of the LED pin

// variables will change:
int button = 0;         // variable for reading the pushbutton status
int rotDirection = 0;


void setup() {
  // initialize the LED pin as an output:
  pinMode(ledPin, OUTPUT);
  // initialize the pushbutton pin as an input:
  pinMode(buttonPin, INPUT_PULLUP);
  pinMode(pwm, OUTPUT);
  pinMode(in1, OUTPUT);
  pinMode(in2, OUTPUT);
  
  // Set initial rotation direction
  digitalWrite(in1, HIGH);
  digitalWrite(in2, LOW);

}


enum CT {WAIT, DOWN, UP, TIMER };   //The 4 possible states of the CT
CT ctstate = WAIT;                                          //Start state is WAIT



void goup() {
  if (millis() - chrono >= delaya) {
    chrono - millis();
   digitalWrite(ledPin, HIGH);
   digitalWrite(in1,LOW) ;
   digitalWrite(in2,HIGH) ;
   analogWrite(pwm,255) ;/* setting pwm of the motor --255= 100%  64= 25%  */
   delay (2500); /* timer of 4 seconds - uninterruptable */
  }
}

void godown() {
  if (millis() - chrono >= delaya) {
    chrono - millis();
   digitalWrite(ledPin, HIGH);
   digitalWrite(in1,HIGH) ;
   digitalWrite(in2,LOW) ;
   analogWrite(pwm,64) ;/* setting pwm of the motor --255= 100%  64= 25%  */
   delay (7000);/* timer of 7 seconds - uninterruptable */
  }
 
}

void timer() {
  if (millis() - chrono >= delayT) {
    chrono - millis();
    delay (12000);
  }

}
void CTtesterstate() {         //The CT state machine
  switch (ctstate) {              //Depending on the state
    case WAIT: {                    //State is WAIT
      if (button == LOW)          //If a button has been pressed
        ctstate = DOWN;          //State is now DOWN
      break;                          //Get out of switch
    }
    case DOWN: {    //State is Down
      godown();
      if (button == LOW)          //If a button is pressed
         ctstate = UP;             //State is now UP
      else ctstate = TIMER;   
       break;                         //Get out of switch
     }
    case TIMER: {             //State is TIMER
      if (button == LOW)
         ctstate = UP;
     else timer();
      ctstate = UP;             //State is now UP
      break;                          //Get out of switch 
  }
    case UP: {             //State is UP
      goup();
      ctstate = WAIT;             //State is now Wait
      break;                          //Get out of switch 
  }
 }
}
void loop() {
  

  // read the state of the pushbutton value:
  button = digitalRead(buttonPin);

  // check if the pushbutton is pressed. If it is, the button is low:
  if (button == LOW) {
    // turn LED on:
    digitalWrite(ledPin, HIGH);
  } else {
    // turn LED off:
    digitalWrite(ledPin, LOW);
  } 
  
  CTtesterstate();  //GO - run
}

Currently, the movements work as desired. The issue I am encountering is the button trigger starts the FSM from the WAIT state to the DOWN. From there, the states continue to change even without the button triggering the change. I've spent days learning and have been developing the code to make a more robust program to achieve my goals. I'm looking for some guidance on:

  1. Why the states keep changing
  2. if my use of chrono and millis for the timer makes sense.
    chrono - millis();

What is the purpose of this ?

Did you perhaps mean

    chrono = millis();

There are three long delays in the sketch. Once you turn them into millis() timers then the sketch will run better and you can press buttons at any time.

An Arduino Uno has 16 bit integers, the two hundred and thirty thousand will not fit in 16 bits.

const int delayT = 230000;

You can use "unsigned long" for everything that has to do with millis().

Have you read this: The Finite State Machine | Majenko Technologies
Don't be afraid to use transitional states.
I call them ..._INIT in my millis_and_finite_state_machine.ino example.

When using millis() and a Finite State Machine it works always in the same way:
The loop() runs fast and many times per second. In a state the millis() is checked. At the end of the interval the state is set to the next state (or another state). I don't see that you change the state at the end of a interval.

Please make the text of the code look nice. Make all indents correct. I am serious, every space and every comma should be at the right place. Then you can see with a glance what the code is doing. You can use Ctrl+T in the Arduino IDE or use your own text layout.

From there, the states continue to change even without the button triggering the change.

since you're only testing for the state of the button input, as soon as you press the button, the state changes and advances before you have a chance to release the button

the code needs to recognize a button press each iteration thru you state machine. A button press is a transition from not pressed to pressed. code needs to track the previous state of the button And may need to debounce by adding a short delay after each change