Help with pushbutton to start a loop with debounce? plus IR beam break as well

Hello everyone,

Video link of what I build and I want I am trying desperately to be programmed:

Video of the physical project

In this video I am manually controlling the setter and sweeper via 4 HJ controllers

I am very new at all of this. following a tread https://forum.arduino.cc/index.php?topic=194009.0#quickreply I think I figured out how to add the push button… however in the tread it is not exactly clear how to add the debounce to that code in that example. They reference at tutorial at https://www.arduino.cc/en/Tutorial/Debounce but I am not sure yet how to adapt that to the example code in that thread.

So I will include my code below if someone could please help me learn and apply this to my code.

I made a miniature pinsetter for a short movie and and it needs to run automatically I have annotated my code to show what is going on at what point during the movements.

So what I would like to happen:

FIRST bit of code:

the user will fill the pin setter full of bowling pins and then press a button to have the setter lower and place the pins on the alley. Then the setter will then return to its upper position.

SECOND Bit of code:

I would like a IR Beambreak sensor trigger (by the bowling ball rolling past) the next set of code where the setter comes down picks up the pins setter goes up sweeper sweeps and the pins are put back down.

LAST Bit of Code:

Then I want the beam break to then again wait for the next roll of the ball to trigger the last part of the code to clear the alley.

I really want to learn how to do this correctly!!!

#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>


// Bowling Alley Pinsetter and Sweeper Sequence
// Servos A,B, & C are all 4.5 turn servos Winch Servo HS-785HB
// Servo D is a small 180 degree servo

//Load Adafruit PCA9685 16 channel driver

boolean buttonstate = false;

// IR Breakbeam sensor

//  #define LEDPIN 13
//  #define SENSORPIN 4

#define MAX_PULSE_WIDTH 2150
#define MID_PULSE_WIDTH 1500
#define MIN_PULSE_WIDTH 800

Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();

// The Motor Outputs on PCA9685 board
// motorA = 0
// motorB = 4
// motorC = 8
// motorD = 12

// variables will change:
//int sensorState = 0, lastState=0;         // variable for reading the pushbutton status

void setup() {
  // put your setup code here, to run once:
pinMode(2 ,INPUT_PULLUP);  //activates the internal pull-up resistor


  // IR Breakbeam sensor
  // initialize the LED pin as an output:
  //pinMode(LEDPIN, OUTPUT);
  // initialize the sensor pin as an input:
  //pinMode(SENSORPIN, INPUT);
  //digitalWrite(SENSORPIN, HIGH); // turn on the pullup
  
  Serial.begin(9600);

  pwm.begin();
  
  pwm.setPWMFreq(60);

}

void loop() {
  // put your main code here, to run repeatedly:
  
  // BUTTON PRESSED TO START ONCE THE PINS HAVE BEEN 
  // FILLED OR REFILLED
  
  // Need a momentary button press here to start 
  // the loop here after the user 
  // has put the bowling pins in the rack and 
  // set the lane for the current frame.
  
  // The first bit of code here below makes the sweeper (motorA)
  // and the setter (motorC) lower and the setter then opens (motorD) 
  // to release the bowling pins and then the 
  // setter and sweeper retrurn to their upper positions

  if(digitalRead(2)==LOW)  // check if button is pushed
   buttonstate = !buttonstate;    //reverse buttonstate value

   if(buttonstate==true)
   {
  
    pwm.writeMicroseconds(8, 1656); // (motorC) sweeper and (motorA)setter lowers together
    pwm.writeMicroseconds(0, 1928);
    delay(6000);
  
    pwm.writeMicroseconds(12, 1889); // (motorD) releases new full set of bowling pins
    delay(4000);
  
    pwm.writeMicroseconds(8, 1178); // (motorC) sweeper and setter raises together
    pwm.writeMicroseconds(0, 1474);
    delay(6000);
    
   
     
    // At this point The pins are in place the program 
    //waits until the IR Breakbeam sensor is triggered 
    //by the ball.
  
    // USER HAS ROLLED THE FIRST BALL OF THE FRAME,
    
    // Ball Rolls Past Sensor (high) 
    //Initiates the next bit of code 
    delay(2000);
  
    pwm.writeMicroseconds(0, 1928); // motorA sweeper lowers
    delay(5000);
  
    pwm.writeMicroseconds(8, 1656); // motorC setter lowers
    delay(6000);
  
    pwm.writeMicroseconds(12, 800); // motorD grabs the still standing bowling pins
    delay(4000);
  
    pwm.writeMicroseconds(8, 1178); // motorC setter raises
    delay(6000);
  
    pwm.writeMicroseconds(4, 1160); // motorB sweeper moves from front to back accross lane
    delay(7000);
  
    pwm.writeMicroseconds(4, 2033); // motorB sweeper moves from back to front accross lane
    delay(7000);
  
    pwm.writeMicroseconds(8, 1656); // motorC lowers
    delay(6000);
  
    pwm.writeMicroseconds(12, 1889); // motorD releases bowling pins, still standing bowling pins
    delay(4000);
  
    pwm.writeMicroseconds(8, 1178); // motorC setter raises
    delay(6000);
  
    pwm.writeMicroseconds(0, 1474); // motorA sweeper raises
    delay(6000);
  
    // SPARE SEQUENCE OF THE FRAME BEGINS
  
    // User rolls the ball Past IR Breakbeam sensor 
    //(high) if else statement???
    delay(2000);
  
    pwm.writeMicroseconds(0, 1928); // motorA sweeper lowers
    delay(5000);
  
    pwm.writeMicroseconds(4, 1160); // motorB sweeper moves from front to back accross lane
    delay(7000);
  
    pwm.writeMicroseconds(4, 2033); // motorB sweeper moves from back to front accross lane
    delay(7000);
  
    pwm.writeMicroseconds(0, 1474); // motorA sweeper raises
    delay(4000);
  
    pwm.writeMicroseconds(12, 800); // Servo D (800us) closes to prepare for bowling pins to be filled
  
    // Needs to loop back in order to resent then restart sequence

   }




}

If you really want to do this correctly, I'd recommend using more of a state machine approach. You have a variable called 'state' and depending on the value, you either check the button press to start, check the IR beam for the fist ball, check the IR beam for the second ball,...

It is not exactly clear to me how many different states you have, but as you get into it, you can add new ones easily.

This allows the loop() function to do what it is designed to do - loop. Every time through, you execute part of the code based on the current state. Some of that code will change the state variable to the next state, etc.

You can google Finite State Machine (FSM) and find libraries to do it, but it is pretty easy to do yourself.

Ok I will try to look into that...

I guess I was just looking at it as "triggers" in a specific order... again I am new at this!

Here’s some code that should be close. It has a few functions so it is more obvious what is intended.

#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>

// Bowling Alley Pinsetter and Sweeper Sequence
// Servos A,B, & C are all 4.5 turn servos Winch Servo HS-785HB
// Servo D is a small 180 degree servo

//Load Adafruit PCA9685 16 channel driver


// IR Breakbeam sensor

//  #define LEDPIN 13
//  #define SENSORPIN 4

#define MAX_PULSE_WIDTH 2150
#define MID_PULSE_WIDTH 1500
#define MIN_PULSE_WIDTH 800

Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();

// The Motor Outputs on PCA9685 board
// motorA = 0
// motorB = 4
// motorC = 8
// motorD = 12

const byte sweeperVerticalMotorPin = 0;
const byte sweeperHorizontalMotorPin = 4;
const byte setterMotorPin = 8;
const byte releaseMotorPin = 12;

// variables will change:
//int sensorState = 0, lastState=0;         // variable for reading the pushbutton status

int lastButtonState;
const byte buttonPin = 2;

enum states { WAIT_FOR_START, WAIT_FOR_BALL1, WAIT_FOR_BALL2 };
int state;

void setup() {

  pinMode(buttonPin , INPUT_PULLUP); //activates the internal pull-up resistor


  // IR Breakbeam sensor
  // initialize the LED pin as an output:
  //pinMode(LEDPIN, OUTPUT);
  // initialize the sensor pin as an input:
  //pinMode(SENSORPIN, INPUT);
  //digitalWrite(SENSORPIN, HIGH); // turn on the pullup

  Serial.begin(9600);
  pwm.begin();
  pwm.setPWMFreq(60);
}


void loop() {

  int buttonState = digitalRead(buttonPin);

  // BUTTON PRESSED TO START ONCE THE PINS HAVE BEEN
  // FILLED OR REFILLED

  // Need a momentary button press here to start
  // the loop here after the user
  // has put the bowling pins in the rack and
  // set the lane for the current frame.

  switch (state) {
    case WAIT_FOR_START:
      if ( buttonState != lastButtonState ) {
        if ( buttonState == LOW ) {
          // button has been pressed, set pins and move to next state
          setPins();
          state = WAIT_FOR_BALL1;
        }
      }
      lastButtonState = buttonState;
      break;

    case WAIT_FOR_BALL1:
      if (checkIRBeam() == true ) {
        // the beam is broken so the ball has passed
        cyclePins();
        state = WAIT_FOR_BALL2;
      }
      break;

    case WAIT_FOR_BALL2:
      if (checkIRBeam() == true ) {
        // the beam is broken so the ball has passed
        sweepPins();
        state = WAIT_FOR_START;
      }
      break;
  }
}


bool checkIRBeam() {

  // At this point The pins are in place the program
  //waits until the IR Breakbeam sensor is triggered
  //by the ball.

  // return true if the beam is broken
  // USER HAS ROLLED THE FIRST BALL OF THE FRAME,

  // Ball Rolls Past Sensor (high)
  //Initiates the next bit of code
  delay(2000);
  return true;
}

void sweeperUp() {
  // move sweeper to the up position
  pwm.writeMicroseconds(sweeperVerticalMotorPin, 1474);
}

void sweeperDown() {
  // move sweeper to the down position
  pwm.writeMicroseconds(sweeperVerticalMotorPin, 1928);
}

void sweeperFront() {
  // move sweeper to the front position
  pwm.writeMicroseconds(sweeperHorizontalMotorPin, 2033); // motorB sweeper moves from back to front accross lane
}

void sweeperBack() {
  // move sweeper to the front position
  pwm.writeMicroseconds(sweeperHorizontalMotorPin, 1160); // motorB sweeper moves from front to back accross lane
}

void setterUp() {
  // move pin setter to the up position
  pwm.writeMicroseconds(setterMotorPin, 1178);
}

void setterDown() {
  // move pin setter to the down position
  pwm.writeMicroseconds(setterMotorPin, 1656);
}

void releasePins() {
  // release bowling pins
  pwm.writeMicroseconds(releaseMotorPin, 1889);
}

void grabPins() {
  // grab bowling pins
  pwm.writeMicroseconds(releaseMotorPin, 800);
}

void setPins() {
  // The first bit of code here below makes the sweeper (motorA)
  // and the setter (motorC) lower and the setter then opens (motorD)
  // to release the bowling pins and then the
  // setter and sweeper retrurn to their upper positions

  setterDown();
  sweeperDown();
  delay(6000);

  releasePins();
  delay(4000);

  setterUp();
  sweeperUp();
  delay(6000);
}


void cyclePins() {
  sweeperDown();
  delay(5000);

  setterDown();
  delay(6000);

  grabPins();
  delay(4000);

  setterUp();
  delay(6000);

  sweeperBack(); // motorB sweeper moves from front to back accross lane
  delay(7000);

  sweeperFront(); // motorB sweeper moves from back to front accross lane
  delay(7000);

  setterDown();
  delay(6000);

  releasePins();
  delay(4000);

  setterUp();
  delay(6000);

  sweeperUp();
  delay(6000);
}


void sweepPins() {
  sweeperDown();
  delay(5000);

  sweeperBack();
  delay(7000);

  sweeperFront();
  delay(7000);

  sweeperUp();
  delay(4000);

  grabPins(); // closes to prepare for bowling pins to be filled
}