// https://wokwi.com/projects/418664622634574849
# include <Servo.h> //Importing the servo library
Servo diverter; //Making an instance for my servo used to divert the marbles to one path or the other
//defining inputs
const int lightMode = 4;
const int lightToggle = 6;
const int pathMode = 2;
const int pathToggle = 3;
const byte ledPin[] = {10, 11, 12, 13};
const byte numLEDs = sizeof ledPin / sizeof *ledPin;
const char *ledTags[] = {"red", "yellow", "blue", "green"};
//defining outputs
const int servoPosition = 5;
// angles for the diverter servo.
const int diverterLEFT = 35;
const int diverterRIGHT = 145;
const int servoPowerRelay = 7;
const int motorPowerRelay = 8;
// defining variables and constants
bool pathAuto = false; //this will be reference to tell if pathing is in automatic or manual
bool lightAuto = false; //this will be reference to tell if lighting is in automatic or manual
const int pathRate = 777; // was 4000 interval for switching paths when in automatic
const int lightRate = 333; //was 500 interval for switching LEDs when in automatic
bool pathA = true; //one servo value found by trial and error to effectively path the marble
//const int pathB = false; //the other servo value found by trial and error to effectively path the marble
//int path = pathA; //holder for current path state
const int debounceTime = 20; // debounce constant
const int keyRepeat = 300; // repeat rate for buttons
unsigned long currentMillis = 0; //this will be used as an ever progressing timeline
unsigned long pathSwitched = 0; // this will hold the time that the path last changed; used in automatic mode
unsigned long lightSwitched = 0; // this will hold the time that the LED tower last changed; used in automatic mode
void setup() {
Serial.begin(9600);
Serial.println("Jello Whirled!\n");
pinMode(lightMode, INPUT_PULLUP); //this will look for UI to switch between manual and automatic lighting
pinMode(lightToggle, INPUT_PULLUP); //this will look for UI to switch current light state when in manual
pinMode(pathMode, INPUT_PULLUP); //this will look for UI to switch between manual and automatic pathing
pinMode(pathToggle, INPUT_PULLUP); //this will look for UI to switch current path state when in manual
diverter.attach(5); //this will send one of two values to the servo for pathing control
//these will set two pins to output and constant high as they're energizing the optoisolator on power relays
pinMode(servoPowerRelay, OUTPUT);
digitalWrite(servoPowerRelay, HIGH);
pinMode(motorPowerRelay, OUTPUT);
digitalWrite(motorPowerRelay, HIGH);
//these will be the wires activating a battery of relays feeding the LED arrays
for (byte ii = 0; ii < numLEDs; ii++) pinMode(ledPin[ii], OUTPUT);
//this sets up the two UI controlled systems in a default starting state so that an LED is lit and the servo is positioned properly in case the system was previously shut off
//while the servo was mid move
diverter.write(diverterLEFT);
lightSomeLED();
//Serial.println("end of setup");
//delay(5000);
}
void loop() {
//this will take the current reading of millis and pass it as a placeholder and then run through the functions which are where the logic lies.
//Serial.println("loop");
currentMillis = millis();
//Serial.println("currentMillis");
switchLightMode();
//Serial.println("lightMode");
switchPathMode();
//Serial.println("pathMode");
changeLED();
//Serial.println("ledChange");
changePath();
//Serial.println("pathChange");
}
# define PRESST LOW
void switchLightMode() {
static bool lastButton = false;
static unsigned long lastTime;
bool thisButton = digitalRead(lightMode) == PRESST;
if (currentMillis - lastTime > debounceTime) {
if (lastButton != thisButton) {
if (thisButton) {
lightAuto = !lightAuto;
Serial.print("light Mode ");
Serial.println(lightAuto ? "automatic" : "manual");
}
lastTime = currentMillis;
lastButton = thisButton;
}
}
}
void switchPathMode() {
static bool lastButton = false;
static unsigned long lastTime;
bool thisButton = digitalRead(pathMode) == PRESST;
if (currentMillis - lastTime > debounceTime) {
if (lastButton != thisButton) {
if (thisButton) {
pathAuto = !pathAuto;
Serial.print("path Mode ");
Serial.println(pathAuto ? "automatic" : "manual");
}
lastTime = currentMillis;
lastButton = thisButton;
}
}
}
int lightSomeLED()
{
static int nowShowing = -1; // not for long
int theLED;
theLED = random(1, numLEDs);
theLED = nowShowing + theLED;
if (theLED >= numLEDs) theLED -= numLEDs;
for (byte ii = 0; ii < numLEDs; ii++) {
if (theLED == ii) digitalWrite(ledPin[theLED], HIGH);
else digitalWrite(ledPin[ii], LOW);
}
nowShowing = theLED;
return theLED;
}
int lightSomeLED_0()
{
static int nowShowing = -1; // not for long
int theLED;
// just can't use the same LED! Pick a new one.
do
theLED = random(0, numLEDs);
while (theLED == nowShowing);
nowShowing = theLED;
for (byte ii = 0; ii < numLEDs; ii++) {
if (theLED == ii) digitalWrite(ledPin[theLED], HIGH);
else digitalWrite(ledPin[ii], LOW);
}
return theLED;
}
void changeLED() {
static unsigned long lastTime;
if (lightAuto == true) {
//Serial.println("lightAuto == true");
if (currentMillis - lightSwitched >= lightRate) {
lightSomeLED();
lightSwitched = currentMillis;
}
} else {
if (currentMillis - lastTime > keyRepeat) {
if (digitalRead(lightToggle) == LOW) {
int theLED = lightSomeLED();
lastTime = currentMillis;
Serial.print("light switched on ");
Serial.println(ledTags[theLED]);
}
}
}
}
void changePath() {
static unsigned long lastTime;
static unsigned long lastManualTime;
if (pathAuto == true) {
if (currentMillis - lastTime > pathRate) {
if (pathA == true) {
diverter.write(diverterLEFT);
pathA = false;
pathSwitched = currentMillis;
Serial.print("LEFT ");
Serial.println(diverter.read());
} else {
diverter.write(diverterRIGHT);
pathA = true;
pathSwitched = currentMillis;
Serial.print("RIGHT ");
Serial.println(diverter.read());
}
lastTime = currentMillis;
}
}
else {
if (currentMillis - lastManualTime > keyRepeat) {
if (digitalRead(pathToggle) == LOW) {
if (pathA) {
diverter.write(diverterRIGHT);
Serial.println("pathA is true");
}
else {
diverter.write(diverterLEFT);
Serial.println("pathA is not true");
}
pathA = !pathA;
lastManualTime = currentMillis;
}
}
}
}