#include <AccelStepper.h>
#include <Bounce2.h>
//INPUT to read Flair signal on DMX
const byte dmxPinAll = X;
const byte dmxPin00 = X;
const byte dmxPin01 = X;
const byte dmxPin02 = X;
const byte dmxPin03 = X;
const byte dmxPin04 = X;
const byte dmxPin05 = X;
//OUTPUT to MOSFETS to trigger solenoids
//const byte solenoidAPin = X;
//const byte solenoidBPin = X;
//const byte solenoidCPin = X;
//const byte solenoidDPin = X;
//const byte solenoidEPin = X;
//const byte solenoidFPin = X;
//INPUT to read button input to trigger Solenoids
const byte solenoidAButton = X;
const byte solenoidBButton = X;
const byte solenoidCButton = X;
//const byte solenoidDButton = 10;
//const byte solenoidEButton = 11;
//const byte solenoidFButton = 12;
//Stepper controls (A) with a switch variable
//for potential future on/off switch
const byte stepperAStepPin = x;
const byte stepperADirPin = x;
const byte stepperASwitchPin = x;
//Stepper controls (B) with a switch variable
//for potential future on/off switch
const byte stepperBStepPin = x;
const byte stepperBDirPin = x;
const byte stepperBSwitchPin = x;
//Stepper controls (C) with a switch variable
//for potential future on/off switch
const byte stepperCStepPin = x;
const byte stepperCDirPin = x;
const byte stepperCSwitchPin = x;
//Variable to hold the current state of the
//Flair signal. Default to 2 to prevent accidental
//behavior at startup because 0 is 'ON'
const byte dmxAllState = 2;
const byte dmx00State = 2;
const byte dmx01State = 2;
const byte dmx02State = 2;
const byte dmx03State = 2;
const byte dmx04State = 2;
const byte dmx05State = 2;
//Variable to determine if stepper motor should be active
const bool stepperAGo = FALSE;
const bool stepperBGo = FALSE;
const bool stepperCGo = FALSE;
//variable to determine if stepper motor received
//killswitch command
volatile bool KILLSwitchPressed = FALSE;
volatile bool stepperAStop = FALSE;
volatile bool stepperBStop = FALSE;
volatile bool stepperCStop = FALSE;
//Variable to hold the millis() at time of
//a solenoid button being pressed
uint32_t solenoidATimer = 0;
uint32_t solenoidBTimer = 0;
uint32_t solenoidCTimer = 0;
//uint32_t solenoidDTimer = 0;
//uint32_t solenoidETimer = 0;
//uint32_t solenoidFTimer = 0;
//variable to hold the designated time in milliseconds
//that the solenoids should be active
const int solenoidDuration = 500;
//variable to hold the designated time in milliseconds
//before any solenoid can be triggered consecutively
const int solenoidCoolOff = 2000;
//Current time global variable, called at beginning of each loop
//to be available to any function
int32_t currentTime = 0;
//Instantiate bounce class objects for each button
//that will require bouncing
Bounce2::Button bounceSolenoidA = Bounce2::Button();
Bounce2::Button bounceSolenoidB = Bounce2::Button();
Bounce2::Button bounceSolenoidC = Bounce2::Button();
//Bounce2::Button bounceSolenoidD = Bounce2::Button();
//Bounce2::Button bounceSolenoidE = Bounce2::Button();
//Bounce2::Button bounceSolenoidF = Bounce2::Button();
//Instantiate bounce class objects for each rotary buttone
//that will require bouncing
Bounce2::Button bounceRotSwitchA = Bounce2::Button();
Bounce2::Button bounceRotSwitchB = Bounce2::Button();
Bounce2::Button bounceRotSwitchC = Bounce2::Button();
//Instantiations of AccelStepper function
//one for each motor
AccelStepper stepperA(AccelStepper::DRIVER , stepperAStepPin, stepperADirPin);
AccelStepper stepperB(AccelStepper::DRIVER , stepperBStepPin, stepperBDirPin);
AccelStepper stepperC(AccelStepper::DRIVER , stepperCStepPin, stepperCDirPin);
void setup() {
// put your setup code here, to run once:
//set killswitch pin to HIGH
pinmode(KILLSwitch, INPUT_PULLUP);
//set killswitch pin as an interrupt
//that triggers on low and calls the ISR
attachInterrupt(digitalPinToInterrupt(KILLSwitch),KILLSwitchISR, LOW);
//set stepper default parameters
stepperA.setMaxSpeed(200.0);
stepperA.setAcceleration(100.0);
stepperA.moveTo(1000);
stepperB.setMaxSpeed(200.0);
stepperB.setAcceleration(100.0);
stepperB.moveTo(1000);
stepperC.setMaxSpeed(200.0);
stepperC.setAcceleration(100.0);
stepperC.moveTo(1000);
//Attach bounce instance to the solenoid INPUT pin
//decide if button will go to ground (INPUT_PULLUP) or not (INPUT)
bounceSolenoidA.attach(solenoidAButton, INPUT_PULLUP);
bounceSolenoidB.attach(solenoidBButton, INPUT_PULLUP);
bounceSolenoidC.attach(solenoidCButton, INPUT_PULLUP);
bounceSolenoidA.attach(solenoidDButton, INPUT_PULLUP);
bounceSolenoidB.attach(solenoidEButton, INPUT_PULLUP);
bounceSolenoidC.attach(solenoidFButton, INPUT_PULLUP);
//Attach bounce instance to the rotary encoder button INPUT pin
bounceRotSwitchA.attach(stepperASwitchPin, INPUT_PULLUP);
bounceRotSwitchB.attach(stepperBSwitchPin, INPUT_PULLUP);
bounceRotSwitchC.attach(stepperCSwitchPin, INPUT_PULLUP);
//Set debounce interval per pin
//solenoid buttons
bounceSolenoidA.interval(25);
bounceSolenoidB.interval(25);
bounceSolenoidC.interval(25);
//stepper buttons
bounceStepperA.interval(25);
bounceStepperB.interval(25);
bounceStepperC.interval(25);
//rotaryencoder buttons
bounceRotSwitchA.interval(25);
bounceRotSwitchB.interval(25);
bounceRotSwitchC.interval(25);
//Set the pressed state for each button pin
//LOW for 'INPUT_PULLUP' or HIGH for 'INPUT'
//solenoid buttons
bounceSolenoidA.setPressedState(LOW);
bounceSolenoidB.setPressedState(LOW);
bounceSolenoidC.setPressedState(LOW);
//stepper buttons
bounceStepperA.setPressedState(LOW);
bounceStepperB.setPressedState(LOW);
bounceStepperC.setPressedState(LOW);
//rotary encoder button pin
bounceRotSwitchA.setPressedState(LOW);
bounceRotSwitchB.setPressedState(LOW);
bounceRotSwitchC.setPressedState(LOW);
//The DMX signal will connect the
//DMX pin 1 to pin 2, which is ground
//Therefore, to read a signal, it has to dump to '0'
//Designate solenoid dmx input pins
pinMode(dmxPinAll, INPUT_PULLUP);
pinMode(dmxPin00, INPUT_PULLUP);
pinMode(dmxPin01, INPUT_PULLUP);
pinMode(dmxPin02, INPUT_PULLUP);
pinMode(dmxPin03, INPUT_PULLUP);
pinMode(dmxPin04, INPUT_PULLUP);
pinMode(dmxPin05, INPUT_PULLUP);
//Designating solenoid trigger pins
pinMode(solenoidAPin, OUTPUT);
pinMode(solenoidBPin, OUTPUT);
pinMode(solenoidCPin, OUTPUT);
//pinMode(solenoidDPin, OUTPUT);
//pinMode(solenoidEPin, OUTPUT);
//pinMode(solenoidFPin, OUTPUT);
//Designating solenoid button input pins
pinMode(solenoidAButton, INPUT_PULLUP);
pinMode(solenoidBButton, INPUT_PULLUP);
pinMode(solenoidCButton, INPUT_PULLUP);
//pinMode(solenoidDButton, INPUT_PULLUP);
//pinMode(solenoidEButton, INPUT_PULLUP);
//pinMode(solenoidFButton, INPUT_PULLUP);
//Designating pins per stepper
pinMode(stepperADirPin, OUTPUT);
pinMode(stepperAStepPin, OUTPUT);
pinMode(stepperASwitchPin , INPUT);
pinMode(stepperBDirPin , OUTPUT);
pinMode(stepperBStepPin , OUTPUT);
pinMode(stepperBSwitchPin, INPUT);
pinMode(stepperCDirPin , OUTPUT);
pinMode(stepperCStepPin , OUTPUT);
pinMode(stepperCSwitchPin, INPUT);
}
void loop() {
// put your main code here, to run repeatedly:
currentTime = millis();
//always check if killswitch was activated
//if it was, run the function to stop the steppers
if (KILLSwitchPressed){
//reset the killswitch
KILLSwitchPressed = FALSE;
fullStop();
}
readDMX ();
//readRotary (); //this function will be fleshed out later
readButtons ();
actOnButtons ();
runmotors();
checkTimer ();
}
//ISR that sets the killswitch to activate
//loop constantly checks if 'Pressed' is TRUE
void KILLSwitchISR(){
KILLSwitchPressed = TRUE;
stepperAGo = FALSE;
stepperBGo = FALSE;
stepperCGo = FALSE;
stepperA.stop();
stepperB.stop();
stepperC.stop();
}
//This will just be polling for a high signal coming in from a single
//lead from the robot. It will probably only ever call the
//solenoid trigger functions, though it may be futureproofing
//to set it up to also call the steppers. That would require there
//being default parameters within the stepper functions or, perhaps
//more simply, having functions that set the paramters separately,
//then wait for the stepper to be called. More research needed.
void readDMX () {
dmxAllState = digitalRead(dmxPinAll);
if (robotTriggerState == 1){} //while pin reads HIGH, nothing is happening, so do nothing...for now
if (robotTriggerState == 0){
//write code to trigger all solenoids
solenoidAGo();
solenoidBGo();
solenoidCGo();
stepperAGo = TRUE;
stepperBGo = TRUE;
stepperCGo = TRUE;
}
dmx00State = digitalRead(dmxPin00);
if (robotTriggerState == 1){} //while pin reads HIGH, nothing is happening, so do nothing...for now
if (robotTriggerState == 0){
solenoidAGo();
}
dmx01State = digitalRead(dmxPin01);
if (robotTriggerState == 1){} //while pin reads HIGH, nothing is happening, so do nothing...for now
if (robotTriggerState == 0){
solenoidBGo();
}
dmx02State = digitalRead(dmxPin02);
if (robotTriggerState == 1){} //while pin reads HIGH, nothing is happening, so do nothing...for now
if (robotTriggerState == 0){
solenoidCGo();
}
dmx03State = digitalRead(dmxPin03);
if (robotTriggerState == 1){} //while pin reads HIGH, nothing is happening, so do nothing...for now
if (robotTriggerState == 0){
stepperAGo = TRUE;
}
dmx04State = digitalRead(dmxPin04);
if (robotTriggerState == 1){} //while pin reads HIGH, nothing is happening, so do nothing...for now
if (robotTriggerState == 0){
stepperBGo = TRUE;
}
dmx05State = digitalRead(dmxPin05);
if (robotTriggerState == 1){} //while pin reads HIGH, nothing is happening, so do nothing...for now
if (robotTriggerState == 0){
stepperCGo = TRUE;
}
}
//This will have to read the encoder, but put the data into different
//variables based on a selection. The button on the encoder can likely be used
//to switch between parameters -thus calling separate functions?
//void readRotary (){}
//Need to poll all buttons with a debounce
void readButtons(){
//bounce2 instances need to be called each loop
//solenoid buttons
bounceSolenoidA.update();
bounceSolenoidB.update();
bounceSolenoidC.update();
//bounceSolenoidD.update();
//bounceSolenoidE.update();
//bounceSolenoidF.update();
//stepper buttons
bounceStepperA.update();
bounceStepperB.update();
bounceStepperC.update();
}
}
//This function will take desired steps should any
//button have been pressed
void actOnButtons(){
//if the button update showed 'pressed' as TRUE
//the correlating pin will be written HIGH...so long as
//the preselected cool off period has expired
if (bounceSolenoidA.pressed() && (currentTime - solenoidATimer) >= solenoidCoolOff){
solenoidAGo();
//get time when solenoid pin was triggered
//to be used when timer function is called to set LOW
solenoidATimer = millis();
}
if (bounceSolenoidB.pressed() && (currentTime - solenoidBTimer) >= solenoidCoolOff){
solenoidBGo();
solenoidBTimer = millis();
}
if (bounceSolenoidC.pressed() && (currentTime - solenoidCTimer) >= solenoidCoolOff){
solenoidCGo();
solenoidCTimer = millis();
}
// if (bounceSolenoidD.pressed() && (currentTime - solenoidDTimer) >= solenoidCoolOff){
// solenoidDGo();
// solenoidDTimer = millis();
//}
// if (bounceSolenoidE.pressed() && (currentTime - solenoidETimer) >= solenoidCoolOff){
// solenoidEGo();
// solenoidETimer = millis();
//}
// if (bounceSolenoidF.pressed() && (currentTime - solenoidFTimer) >= solenoidCoolOff){
// solenoidFGo();
// solenoidF Timer = millis();
//}
//
if (bounceStepperA.pressed()){
stepperAGo = TRUE;
}
if (bounceStepperB.pressed()){
stepperBGo = TRUE;
}
if (bounceStepperB.pressed()){
stepperCGo = TRUE;
}
}
//This is a function to process the input from the rotary encoders
void rotaryEncoderInput(){}
//This function checks to see if the solenoids have been 'on' long enough
//If they have been HIGH more than the designated # of millis()
//it will set the bool that actOnButtons checks to FALSE
void checkTimer(){
if (currentTime - solenoidATimer >= solenoidDuration){
digitalWrite(solenoidAPin, LOW);
}
if (currentTime - solenoidBTimer >= solenoidDuration){
digitalWrite(solenoidBPin, LOW);
}
if (currentTime - solenoidCTimer >= solenoidDuration){
digitalWrite(solenoidCPin, LOW);
}
// if (currentTime - solenoidDTimer >= solenoidDuration){
// digitalWrite(solenoidDPin, LOW);
//}
// if (currentTime - solenoidETimer >= solenoidDuration){
// digitalWrite(solenoidEPin, LOW);
//}
// if (currentTime - solenoidFTimer >= solenoidDuration){
// digitalWrite(solenoidFPin, LOW);
//}
}
//These functions trigger solenoids exclusively, allowing these functions to be called
//by any other function, rather than writing all the code each time.
void solenoidAGo(){
digitalWrite(solenoidAPin, HIGH);
}
void solenoidBGo(){
digitalWrite(solenoidBPin, HIGH);
}
void solenoidCGo(){
digitalWrite(solenoidCPin, HIGH);
}
//void solenoidDGo(){
// digitalWrite(solenoidDPin, HIGH);
//}
//void solenoidEGo(){
// digitalWrite(solenoidEPin, HIGH);
//}
//void solenoidFGo(){
// digitalWrite(solenoidFPin, HIGH);
//}
//This function will check if motors are supposed to be running
//and then run them until they reach the set position