Hello everyone,
I hope I'm pasting my code properly; I saw a thread stating the experts on here like full code dumps, not snippets. If I need to retry please let me know.
A quick bit of context: I'm making a project for a class that involves some UI to manipulate lights and pathing of an automated marble run. I cannot for the life of me get my servo to act properly. This is frustrating for many reasons, not the least of which is my LEDs were built using ideas from the delay without delay and time blocking mega threads on here and work fine; I then tried building a second time with modifications to make my servo be manipulated and one of the if loops seems to be executing regardless of if the conditions are met.
I am very sure that the issue is the code and not an electrical problem; I will elaborate more if needed, but the strongest argument is that using Serial.println I can watch a boolean flip back and forth even when I (at least in terms of intent) lock it behind an If statement. it is the else branch in the changePath function that begins with println "path mode manual" to the end of the code.
I've tried rewriting it thinking I had a silly bug I couldn't find and the issue persisted. I have tried putting the if statement to two checks (pulled up input == LOW and a time block) as well as nesting them. I also once tried just making it input == low as the condition and using the serial monitor as well as confirming voltage with my DMM I can see that the button is HIGH. Yet, the pathA boolean will still swap back and forth.
I then wondered if I had inadvertently used that boolean earlier in my code but didn't see any, and on top of that, even if I had, that still doesn't explain why it runs through anything other than printing "pathMode manual" and "pathToggle Value"; at that point, there are nested If statements which check for time to debounce (an idea given by the aforementioned thread) as well as reading my pin for the pathToggle UI once the build is finished.
I can't think of what else it can be. Again, because of what I've already done to try and debug, I'm very sure it is code. In the event someone disagrees, let me know what you want to know on the hardware side and I'll provide that information.
Thanks in advance, everyone.
#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;
//defining outputs
const int servoPosition = 5;
const int servoPowerRelay = 7;
const int motorPowerRelay = 8;
const int red = 10;
const int yellow = 11;
const int blue = 12;
const int green = 13;
// 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 = 4000; //interval for switching paths when in automatic
const int lightRate = 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 buttonPress = 300; //this will be referenced as part of a software debounce
unsigned long currentMillis = 0; //this will be used as an ever progressing timeline
unsigned long lightModeButtonMillis = 0; //this will be referenced as part of a software debounce
unsigned long lightStateButtonMillis = 0; //this will be referenced as part of a software debounce
unsigned long servoModeButtonMillis = 0; //this will be referenced as part of a software debounce
unsigned long servoStateButtonMillis = 0; //this will be referenced as part of a software debounce
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);
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
pinMode(red, OUTPUT);
pinMode(yellow, OUTPUT);
pinMode(blue, OUTPUT);
pinMode(green, 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
//delay(2000);
diverter.write(0);
digitalWrite(random(10, 14), HIGH); //this selects a random LED output pin to activate
//digitalWrite(blue, HIGH);
//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");
}
void switchLightMode() {
//this function debounces by referencing variables and when the button is pressed, changes the state of the lightAuto bool
if (millis() - lightModeButtonMillis >= buttonPress) {
if (digitalRead(lightMode) == LOW) {
lightAuto = !lightAuto;
lightModeButtonMillis = millis();
Serial.println("lightModeButton");
//delay(500);
}
}
}
void switchPathMode() {
//this function debounces by referencing variables and when the button is pressed, changes the state of the lightAuto bool
if (millis() - servoModeButtonMillis >= buttonPress) {
if (digitalRead(pathMode) == LOW) {
pathAuto = !pathAuto;
servoModeButtonMillis = millis();
Serial.println("pathModeButton");
//delay(500);
}
}
}
void changeLED() {
if (lightAuto == true) {
//Serial.println("lightAuto == true");
if (currentMillis - lightSwitched >= lightRate) {
digitalWrite(red, LOW);
digitalWrite(yellow, LOW);
digitalWrite(blue, LOW);
digitalWrite(green, LOW);
digitalWrite(random(10, 14), HIGH); //this selects a random LED output pin to activate
lightSwitched = currentMillis;
}
} else {
if (millis() - lightStateButtonMillis >= buttonPress) {
if (digitalRead(lightToggle) == LOW) {
digitalWrite(red, LOW);
digitalWrite(yellow, LOW);
digitalWrite(blue, LOW);
digitalWrite(green, LOW);
digitalWrite(random(10, 14), HIGH); //this selects a random LED output pin to activate
lightStateButtonMillis = millis();
Serial.println("lightSwitchButton");
//delay(500);
}
}
}
}
void changePath() {
if (pathAuto == true) {
Serial.println("pathMode auto");
//delay(500);
if (currentMillis - pathSwitched >= pathRate) {
if (pathA == true) {
diverter.write(0);
pathA = false;
pathSwitched = currentMillis;
Serial.println("position 0");
} else {
diverter.write(20);
pathA = true;
pathSwitched = currentMillis;
Serial.println("position 20");
}
}
} else {
Serial.println("pathMode manual");
//delay(500);
Serial.print("pathToggleValue: ");
Serial.println(digitalRead(pathToggle));
if (currentMillis - servoStateButtonMillis >= buttonPress) {
if (digitalRead(pathToggle == LOW)) {
if (pathA != true) {
diverter.write(0);
Serial.println("pathA is not true");
pathA = true;
servoStateButtonMillis = currentMillis;
//delay(500);
}
else {
diverter.write(20);
Serial.println("pathA is true");
pathA = false;
servoStateButtonMillis = currentMillis;
//delay(500);
}
}
}
}
}
/*
//if (millis() - servoStateButtonMillis >= buttonPress && digitalRead(pathToggle == LOW)){
Serial.println("pathSwitchButton");
delay(500);
Serial.println(pathA);
if (pathA != true) {
Serial.println("if block");
delay(500);
diverter.write(0);
pathA = true;
servoStateButtonMillis = currentMillis;
Serial.println(pathA);
} else {
Serial.println("else block");
delay(500);
diverter.write(20);
pathA = false;
servoStateButtonMillis = currentMillis;
Serial.println(pathA);
}
}
}
}
} */