Ok so first off here is the code modified again and I still for the life of me can not figure out this case and state stuff but hell it is working somewhat I think attached is another video that shows what the program does now and herewith my code.
#include <LiquidCrystal.h>
const int RS = 8;
const int EN = 9;
const int D4 = 10;
const int D5 = 11;
const int D6 = 12;
const int D7 = 13;
const int BAUD_RATE = 9600;
const int LED_Prestage = 2;
const int LED_Stage = 3;
const int LED_Y1 = 4;
const int LED_Y2 = 6;
const int LED_Y3 = 7;
const int LED_Start = A2;
const int LED_RED_Light = A3;
const int Pre_Stage_Sensor = A0;
const int Stage_Sensor = A1;
const int Finish_Sensor = A4;
const int Start_Button = 5;
int state = 0;
bool StartFlag = false;
const String MESSAGE = "System Ready.";
double countdownStart;
double raceStart;
bool FinishFlag;
double FinishET;
LiquidCrystal lcd(RS, EN, D4, D5, D6, D7);
void setup() {
pinMode(LED_Prestage, OUTPUT);
pinMode(LED_Stage, OUTPUT);
pinMode(LED_Y1, OUTPUT);
pinMode(LED_Y2, OUTPUT);
pinMode(LED_Y3, OUTPUT);
pinMode(LED_Start, OUTPUT);
pinMode(LED_RED_Light, OUTPUT);
pinMode(Pre_Stage_Sensor, INPUT);
pinMode(Stage_Sensor, INPUT);
pinMode(Finish_Sensor, INPUT);
pinMode(Start_Button, INPUT_PULLUP);
Serial.begin(BAUD_RATE);
lcd.begin(16, 2);
lcd.setCursor(0, 1);
lcd.print(MESSAGE);
delay(2000);
lcd.clear();
}
void loop()
{
int Pre_Stage_Sensor_Value = analogRead(Pre_Stage_Sensor);
int Stage_Sensor_Value = analogRead(Stage_Sensor);
int Finish_Sensor_Value = analogRead (Finish_Sensor);
switch (state) {
case 0: // Standby State
if (Pre_Stage_Sensor_Value > 500) {
digitalWrite(LED_Prestage, LOW);}
else{
digitalWrite(LED_Prestage, HIGH);
}
case 1:// Vehicle Staging State
if (Stage_Sensor_Value < 500) {
digitalWrite(LED_Stage, HIGH);
}
else{
digitalWrite(LED_Stage, LOW);
}
if (Stage_Sensor_Value < 500){
lcd.clear();
lcd.print("Vehicle Ready");
delay(500);
}
else {
lcd.clear();
lcd.print("Please Stage");
delay(500);
}
case 2:
if (digitalRead(Start_Button) == LOW)
{
countdownStart = millis();
state++;
}
break;
case 3:
if (millis() - countdownStart > 2000)
{
digitalWrite(LED_Y3, LOW);
digitalWrite(LED_Start, HIGH);
StartFlag = true;
}
else if (millis() - countdownStart > 1500)
{
digitalWrite(LED_Y2, LOW);
digitalWrite(LED_Y3, HIGH);
}
else if (millis() - countdownStart > 1000)
{
digitalWrite(LED_Y1, LOW);
digitalWrite(LED_Y2, HIGH);
}
else if (millis() - countdownStart > 500)
{
digitalWrite(LED_Y1, HIGH);
}
case 4:
if (analogRead(Stage_Sensor) > 500 && !StartFlag)
{
digitalWrite(LED_RED_Light, HIGH);
}
case 5:
if ((millis() - countdownStart > 2000))
{
lcd.clear();
lcd.print("GO");
raceStart= millis() - countdownStart;
delay (500);
lcd.clear();
lcd.print(raceStart);
}
if (analogRead(Finish_Sensor) <500)
{ FinishFlag= true;
FinishET = millis() - raceStart;
lcd.clear();
lcd.print("Finish ET:");
lcd.setCursor(0, 1);
lcd.print(FinishET / 100, 3);
}
}}// END LOOP BRACKETS
I have researched some lights libraries ect but they do not include sensors or timers in this extent I would appreciate it once again if you can have a look and point me in the right direction of what to do with this code. I still can say tank you enough to te people trying to help as I would have still been by V1 if it was not for you on this platform. So thank you
Screen Recording 2023-02-21 at 19.07.04.zip (7.7 MB)
As mentioned by @guix above, I recently (in the last 2 weeks) wrote a blog post (https://arduinoplusplus.wordpress.com/2023/02/09/drag-race-start-lights/) about this and published a sketch (ref in comment #21 above) to do what you are doing. Looking at that code or blog may help you.
Looks like you've lost your way somewhat...
The idea of the "states" is that you are only ever in one state at a time... so only that bit of code executes on any given loop. You need to explicitly move to the next state by incrementing the "state" variable (state++)... you seem to have lost that concept completely... only state 2 changes the state variable.
The other major problem is that a switch/case statement is not like an "if" statement... there is no concept of else. A switch statement just has a bunch of labels where the code starts running from "case:0", "case:1" , etc... but when it gets to the end of that block of code it just keeps going... that's why you always need a "break" statement. The only case block that has one is case:2.
These 2 issues will cause some very unexpected behaviour... I suggest you fix these first. Go back to the code in post #4 and post #13 and look at how that code actually works.
You could always check out one of the other examples that others have posted... might get you there quicker. They've already done the hard work.
But IMHO... you'll get more satisfaction if you get your own version working.
Thanks a mill once again yes I have all of the examples open on 3 screens at this stage to see how I can inclement certain aspects of the systems into mine.
guix posted a perfect example of using a Switch Case finite state machine in post 21. Follow his curState variable to control which case to use. Notice the break just before the next case. Also notice the last case sets curState to RESET, which is the name of his first case.
all your doubles are the wrong type to store millis in, replace with..
unsigned long countdownStart;
worked on it a bit..
#include <LiquidCrystal.h>
#define FEET_PER_MILE 5280
#define TRACK_LEN 1320
#define RESET_BTN A5
const byte RS = 8;
const byte EN = 9;
const byte D4 = 10;
const byte D5 = 11;
const byte D6 = 12;
const byte D7 = 13;
const byte BAUD_RATE = 9600;
const byte LED_Prestage = 2;
const byte LED_Stage = 3;
const byte LED_Y1 = 4;
const byte LED_Y2 = 6;
const byte LED_Y3 = 7;
const byte LED_Start = A2;
const byte LED_RED_Light = A3;
const byte Pre_Stage_Sensor = A0;
const byte Stage_Sensor = A1;
const byte Finish_Sensor = A4;
const byte Start_Button = 5;
//define missing slash char for Flip ani..
uint8_t slash[8] = {
0b10000,
0b10000,
0b01000,
0b00100,
0b00100,
0b00010,
0b00001,
0b00001,
};
byte flip = 0;
unsigned long AniMilli = 0;
int IntervalAni = 50;
int state = 0;
bool StartFlag = false;
unsigned long countdownStart;
unsigned long raceStart;
bool FinishFlag;
unsigned long FinishET;
LiquidCrystal lcd(RS, EN, D4, D5, D6, D7);
void setup() {
pinMode(LED_Prestage, OUTPUT);
pinMode(LED_Stage, OUTPUT);
pinMode(LED_Y1, OUTPUT);
pinMode(LED_Y2, OUTPUT);
pinMode(LED_Y3, OUTPUT);
pinMode(LED_Start, OUTPUT);
pinMode(LED_RED_Light, OUTPUT);
/*
pinMode(Pre_Stage_Sensor, INPUT);
pinMode(Stage_Sensor, INPUT);
pinMode(Finish_Sensor, INPUT);*/
pinMode(Start_Button, INPUT_PULLUP);
pinMode(RESET_BTN, INPUT_PULLUP);
//Serial.begin(BAUD_RATE);
Serial.begin(115200);
lcd.begin(16, 2);
lcd.createChar(1, slash);
lcd.setCursor(0, 1);
lcd.print(F("System Ready"));
delay(2000);
lcd.clear();
}
void loop()
{
int Pre_Stage_Sensor_Value = analogRead(Pre_Stage_Sensor);
int Stage_Sensor_Value = analogRead(Stage_Sensor);
int Finish_Sensor_Value = analogRead (Finish_Sensor);
/*
Serial.print("PreStage: ");
Serial.println(Pre_Stage_Sensor_Value);
Serial.print("Stage: ");
Serial.println(Stage_Sensor_Value);
Serial.print("Finish: ");
Serial.println(Finish_Sensor_Value);
Serial.print("State: ");
Serial.println(state);
Serial.println();
delay(2000);
*/
switch (state) {
case 0: // Standby State
if (Pre_Stage_Sensor_Value > 500) {
digitalWrite(LED_Prestage, LOW);
}
else {
digitalWrite(LED_Prestage, HIGH);
state++;//move to next state??
}
break;
case 1:// Vehicle Staging State
if (Stage_Sensor_Value < 500) {
digitalWrite(LED_Stage, HIGH);
}
else {
digitalWrite(LED_Stage, LOW);
}
if (Stage_Sensor_Value < 500) {
lcd.clear();
lcd.print("Vehicle Ready");
delay(500);
state++;
}
else {
lcd.clear();
lcd.print("Please Stage");
delay(500);
}
break;
case 2:
if (Stage_Sensor_Value > 501) {
state--;
}
else
{
if (digitalRead(Start_Button) == LOW)
{
countdownStart = millis();
state++;
}
}
break;
case 3:
if (millis() - countdownStart > 2000)
{
digitalWrite(LED_Y3, LOW);
digitalWrite(LED_Start, HIGH);
StartFlag = true;
state++;
}
else if (millis() - countdownStart > 1500)
{
digitalWrite(LED_Y2, LOW);
digitalWrite(LED_Y3, HIGH);
}
else if (millis() - countdownStart > 1000)
{
digitalWrite(LED_Y1, LOW);
digitalWrite(LED_Y2, HIGH);
}
else if (millis() - countdownStart > 500)
{
digitalWrite(LED_Y1, HIGH);
}
break;
case 4: //check for false start??
if (analogRead(Stage_Sensor) > 500 && !StartFlag)
{
digitalWrite(LED_RED_Light, HIGH);
} else state++;
break;
case 5:
if ((millis() - countdownStart > 2000))
{
lcd.clear();
lcd.print(" GO ");
//raceStart = millis() - countdownStart;??
raceStart = millis();
lcd.print(raceStart);
state++;
}
break;
case 6:
if (analogRead(Finish_Sensor) < 500)
{ if (!FinishFlag)
{ FinishFlag = true;
FinishET = millis() - raceStart;
lcd.clear();
lcd.print("Finish ET:");
float secs = float(FinishET) / 1000;
lcd.print(secs);
lcd.setCursor(0, 1);
lcd.print("mph:");
float fps = (TRACK_LEN / secs);
Serial.print("fps:"); Serial.println(fps, 4);
float mph = (fps / FEET_PER_MILE) / 0.00028;
Serial.print("mph:"); Serial.println(mph, 4);
lcd.print(mph, 4);
state = 7;
}
} else FlipAni();
break;
case 7:
if (digitalRead(RESET_BTN) == LOW)
{
digitalWrite(LED_Start, LOW);
StartFlag = false;
FinishFlag = false;
state = 0;
}
break;
}
}// END LOOP BRACKETS
void FlipAni() {
if (millis() - AniMilli >= IntervalAni)
{
AniMilli = millis();
switch (flip) {
case 0: flip = 1; lcd.setCursor(0, 0); lcd.print("|"); lcd.setCursor(15, 0); lcd.print("|"); break;
case 1: flip = 2; lcd.setCursor(0, 0); lcd.print("/"); lcd.setCursor(15, 0); lcd.print("/"); break;
case 2: flip = 3; lcd.setCursor(0, 0); lcd.print("-"); lcd.setCursor(15, 0); lcd.print("-"); break;
case 3: flip = 4; lcd.setCursor(0, 0); lcd.print("\x01"); lcd.setCursor(15, 0); lcd.print("\x01"); break;
case 4: flip = 0; lcd.setCursor(0, 0); lcd.print("|"); lcd.setCursor(15, 0); lcd.print("|"); break;
}
}
}
lol, raced a few times myself, 50 lap enduros.. fun times.. ![]()
@qubits-us you are a flipping legend I have been getting no sleep to try and figure out why my stuff Is not working and here you come with a working prototype model that even displays the speed I have been going back and fort if I change something something else does not work it drives me insane lol. Look I don't no anything about code before I started this project and everyone above me has been trying to help me sort this out and guide me along the way which I am very thankful for. it looks like I am going to need a bigger board the Arduino mega to run all my lights for pre-stage and stage to the finish line next step is to get te reaction time done and then play with the sensors almost time for a working model I can not wait you just gave me hope again thank you for assisting in this.
Just an update on the sketch, I have sorted out the Random yellow led, and red lights issues and the lights now work perfectly as it should I will share the update with you here so that you can see for yourself haha now I'm getting exited and I think I'm getting the hang of this slowly but shortly (not without the help of all of you especially @red_car & @qubits-us , I am next going to try and move the start time to when the vehicle leaves the stage beam and then once that is done try and do another time system to figure out the reaction time of the driver. If this is all sorted a second lane to be added and then the fun part comes in win lights delay (aka dial in times) and then foul if the second vehicle is not in the second stage beam after 1300mil or 1.3 seconds as per @marco_c's code once again thanks for everyones help I know I sound dumb saying it all the time but hell I don't know code at all and you all are making it an exiting experience. https://wokwi.com/projects/357470578692513793
Start time sorted out now it is time for reaction time struggling but getting there slowly but Shorly, how do I go about displaying (ET:) 10.56 & Reaction Time (RT:) On line 1 and then Speed (MPH) on line two of the screen:
#include <LiquidCrystal.h>
#define FEET_PER_MILE 5280
#define TRACK_LEN 1320
#define RESET_BTN 47
const byte RS = 52;
const byte EN = 49;
const byte D4 = 53;
const byte D5 = 50;
const byte D6 = 51;
const byte D7 = 48;
const byte BAUD_RATE = 9600;
const byte LED_Prestage = 8;
const byte LED_Stage = 7;
const byte LED_Y1 = 6;
const byte LED_Y2 = 5;
const byte LED_Y3 = 4;
const byte LED_Start = 3;
const byte LED_RED_Light = 2;
const byte Pre_Stage_Sensor = A0;
const byte Stage_Sensor = A1;
const byte Finish_Sensor = A2;
const byte Start_Button = 46;
//define missing slash char for Flip ani..
uint8_t slash[8] = {
0b10000,
0b10000,
0b01000,
0b00100,
0b00100,
0b00010,
0b00001,
0b00001,
};
byte flip = 0;
unsigned long AniMilli = 0;
int IntervalAni = 50;
int state = 0;
bool StartFlag = false;
unsigned long countdownStart;
unsigned long raceStart;
unsigned long reactionTime;
bool FinishFlag;
unsigned long FinishET;
LiquidCrystal lcd(RS, EN, D4, D5, D6, D7);
void setup() {
pinMode(LED_Prestage, OUTPUT);
pinMode(LED_Stage, OUTPUT);
pinMode(LED_Y1, OUTPUT);
pinMode(LED_Y2, OUTPUT);
pinMode(LED_Y3, OUTPUT);
pinMode(LED_Start, OUTPUT);
pinMode(LED_RED_Light, OUTPUT);
pinMode(Pre_Stage_Sensor, INPUT);
pinMode(Stage_Sensor, INPUT);
pinMode(Finish_Sensor, INPUT);
pinMode(Start_Button, INPUT_PULLUP);
pinMode(RESET_BTN, INPUT_PULLUP);
//Serial.begin(BAUD_RATE);
Serial.begin(115200);
lcd.begin(16, 2);
lcd.createChar(1, slash);
lcd.setCursor(0, 1);
lcd.print(F("System Ready"));
delay(2000);
lcd.clear();
}
void loop()
{
int Pre_Stage_Sensor_Value = analogRead(Pre_Stage_Sensor);
int Stage_Sensor_Value = analogRead(Stage_Sensor);
int Finish_Sensor_Value = analogRead (Finish_Sensor);
/*
Serial.print("PreStage: ");
Serial.println(Pre_Stage_Sensor_Value);
Serial.print("Stage: ");
Serial.println(Stage_Sensor_Value);
Serial.print("Finish: ");
Serial.println(Finish_Sensor_Value);
Serial.print("State: ");
Serial.println(state);
Serial.println();
delay(2000);
*/
switch (state) {
case 0:
if (Pre_Stage_Sensor_Value > 500) {
digitalWrite(LED_Prestage, LOW);
}
else {
digitalWrite(LED_Prestage, HIGH);
state++;
}
break;
case 1:// Vehicle Staging State
if (Stage_Sensor_Value > 500) {
digitalWrite(LED_Stage, LOW);
}
else {
digitalWrite(LED_Stage, HIGH);
}
if (Stage_Sensor_Value < 500) {
lcd.clear();
lcd.print("Vehicle Ready");
delay(500);
state++;
}
else {
lcd.clear();
lcd.print("Please Stage");
delay(500);
state--;
}
break;
case 2:
if (Stage_Sensor_Value > 501) {
state--;
}
else
{
if (digitalRead(Start_Button) == LOW)
{
countdownStart = millis();
state++;
}
}
break;
case 3:
if (millis() - countdownStart > 2000)
{ //check sensor just before dropping the flag
if (Stage_Sensor_Value < 500){
digitalWrite(LED_Y3, LOW);
digitalWrite(LED_Start, HIGH);
StartFlag = true;
state++;} else{
digitalWrite(LED_Y3, LOW);
digitalWrite(LED_Prestage, LOW);
digitalWrite(LED_Stage, LOW);
digitalWrite(LED_RED_Light, HIGH);
delay(1000);
lcd.clear();
lcd.print("!!Bad Start!!");
state= 7;
}
}
else if (millis() - countdownStart > 1500)
{
digitalWrite(LED_Y2, LOW);
digitalWrite(LED_Y3, HIGH);
}
else if (millis() - countdownStart > 1000)
{
digitalWrite(LED_Y1, LOW);
digitalWrite(LED_Y2, HIGH);
}
else if (millis() - countdownStart > 500)
{
digitalWrite(LED_Y1, HIGH);
}
break;
case 4: //check for false start??
if (analogRead(Stage_Sensor) > 500 && !StartFlag)
{
digitalWrite(LED_RED_Light, HIGH);
lcd.clear();
lcd.print("!!Bad Start!!");
state = 7;
} else state++;
break;
case 5:
if ((millis() - countdownStart > 2000) && analogRead(Stage_Sensor_Value > 500))
{
lcd.clear();
lcd.print(" GO ");
//raceStart = millis() - countdownStart;??
raceStart = millis();
lcd.print(raceStart);
state++;
}
break;
case 6:
if (analogRead(Finish_Sensor) < 500)
{ if (!FinishFlag)
{ FinishFlag = true;
FinishET = millis() - raceStart;
lcd.clear();
lcd.print("ET:");
float secs = float(FinishET) / 1000;
lcd.print(secs);
lcd.setCursor(0, 1);
lcd.print("MPH:");
float fps = (TRACK_LEN / secs);
Serial.print("fps:"); Serial.println(fps, 4);
float mph = (fps / FEET_PER_MILE) / 0.00028;
Serial.print("MPH:"); Serial.println(mph, 4);
lcd.print(mph, 4);
state = 7;
}
} else FlipAni();
break;
case 7:
if (digitalRead(RESET_BTN) == LOW)
{
digitalWrite(LED_Start, LOW);
digitalWrite(LED_Stage, LOW);
digitalWrite(LED_RED_Light, LOW);
StartFlag = false;
FinishFlag = false;
state = 0;
}
break;
}
}// END LOOP BRACKETS
void FlipAni() {
if (millis() - AniMilli >= IntervalAni)
{
AniMilli = millis();
switch (flip) {
case 0: flip = 1; lcd.setCursor(0, 0); lcd.print("|"); lcd.setCursor(15, 0); lcd.print("|"); break;
case 1: flip = 2; lcd.setCursor(0, 0); lcd.print("/"); lcd.setCursor(15, 0); lcd.print("/"); break;
case 2: flip = 3; lcd.setCursor(0, 0); lcd.print("-"); lcd.setCursor(15, 0); lcd.print("-"); break;
case 3: flip = 4; lcd.setCursor(0, 0); lcd.print("\x01"); lcd.setCursor(15, 0); lcd.print("\x01"); break;
case 4: flip = 0; lcd.setCursor(0, 0); lcd.print("|"); lcd.setCursor(15, 0); lcd.print("|"); break;
}
}
}
This function is used to position the cursor within the display before writing the text...
It's a 16x2 display (so columns are numbered 0-15, rows 0-1)
Ok so an update on the Timing System
-
Reaction Time Added (Red Light -003 Reaction Still to be Implemented)
-
LCD Displaying as it should and where I want with all the characters fitting in nicely.
-
Serial Print (Future Time Slip Output) Added ET, RT, MPH for vehicle 1
-
All Lights displaying as they should and counting down with foul start (Red Light)
#include <LiquidCrystal.h>
#define FEET_PER_MILE 5280
#define TRACK_LEN 1320
#define RESET_BTN 47
const byte RS = 52;
const byte EN = 49;
const byte D4 = 53;
const byte D5 = 50;
const byte D6 = 51;
const byte D7 = 48;
const byte BAUD_RATE = 9600;
const byte LED_Prestage = 8;
const byte LED_Stage = 7;
const byte LED_Y1 = 6;
const byte LED_Y2 = 5;
const byte LED_Y3 = 4;
const byte LED_Start = 3;
const byte LED_RED_Light = 2;
const byte Pre_Stage_Sensor = A0;
const byte Stage_Sensor = A1;
const byte Finish_Sensor = A2;
const byte Start_Button = 46;
//define missing slash char for Flip ani..
uint8_t slash[8] = {
0b10000,
0b10000,
0b01000,
0b00100,
0b00100,
0b00010,
0b00001,
0b00001,
};
byte flip = 0;
unsigned long AniMilli = 0;
int IntervalAni = 50;
int state = 0;
bool StartFlag = false;
unsigned long countdownStart;
unsigned long raceStart;
unsigned long reactionTime;
unsigned long vehicleStart;
bool FinishFlag;
unsigned long FinishET;
float ReactSec;
LiquidCrystal lcd(RS, EN, D4, D5, D6, D7);
void setup() {
pinMode(LED_Prestage, OUTPUT);
pinMode(LED_Stage, OUTPUT);
pinMode(LED_Y1, OUTPUT);
pinMode(LED_Y2, OUTPUT);
pinMode(LED_Y3, OUTPUT);
pinMode(LED_Start, OUTPUT);
pinMode(LED_RED_Light, OUTPUT);
pinMode(Pre_Stage_Sensor, INPUT);
pinMode(Stage_Sensor, INPUT);
pinMode(Finish_Sensor, INPUT);
pinMode(Start_Button, INPUT_PULLUP);
pinMode(RESET_BTN, INPUT_PULLUP);
//Serial.begin(BAUD_RATE);
Serial.begin(115200);
lcd.begin(16, 2);
lcd.createChar(1, slash);
lcd.setCursor(0, 1);
lcd.print(F("System Ready"));
delay(2000);
lcd.clear();
}
void loop()
{
int Pre_Stage_Sensor_Value = analogRead(Pre_Stage_Sensor);
int Stage_Sensor_Value = analogRead(Stage_Sensor);
int Finish_Sensor_Value = analogRead (Finish_Sensor);
/*
Serial.print("PreStage: ");
Serial.println(Pre_Stage_Sensor_Value);
Serial.print("Stage: ");
Serial.println(Stage_Sensor_Value);
Serial.print("Finish: ");
Serial.println(Finish_Sensor_Value);
Serial.print("State: ");
Serial.println(state);
Serial.println();
delay(2000);
*/
switch (state) {
case 0:
if (Pre_Stage_Sensor_Value > 500) {
digitalWrite(LED_Prestage, LOW);
}
else {
digitalWrite(LED_Prestage, HIGH);
state++;
}
break;
case 1:// Vehicle Staging State
if (Stage_Sensor_Value > 500) {
digitalWrite(LED_Stage, LOW);
}
else {
digitalWrite(LED_Stage, HIGH);
}
if (Stage_Sensor_Value < 500) {
lcd.clear();
lcd.print("Vehicle Ready");
delay(500);
state++;
}
else {
lcd.clear();
lcd.print("Please Stage");
delay(500);
state--;
}
break;
case 2:
if (Stage_Sensor_Value > 501) {
state--;
}
else
{
if (digitalRead(Start_Button) == LOW)
{
countdownStart = millis();
state++;
}
}
break;
case 3:
if (millis() - countdownStart > 2000)
{ //check sensor just before dropping the flag
if (Stage_Sensor_Value < 500){
digitalWrite(LED_Y3, LOW);
digitalWrite(LED_Start, HIGH);
StartFlag = true;
raceStart = millis();//start counting race from here..
state++;} else{
digitalWrite(LED_Y3, LOW);
digitalWrite(LED_Prestage, LOW);
digitalWrite(LED_Stage, LOW);
digitalWrite(LED_RED_Light, HIGH);
delay(1000);
lcd.clear();
lcd.print("!!Bad Start!!");
state= 7;
}
}
else if (millis() - countdownStart > 1500)
{
digitalWrite(LED_Y2, LOW);
digitalWrite(LED_Y3, HIGH);
}
else if (millis() - countdownStart > 1000)
{
digitalWrite(LED_Y1, LOW);
digitalWrite(LED_Y2, HIGH);
}
else if (millis() - countdownStart > 500)
{
digitalWrite(LED_Y1, HIGH);
}
break;
case 4: //stage to get reaction time
//need to see car move before next state..
if (analogRead(Stage_Sensor) > 500 && StartFlag)
{
vehicleStart = millis();
reactionTime = millis();
state++;
} ;
break;
case 5:
//prints go and reaction time..
if ((millis() - countdownStart > 2000) && analogRead(Stage_Sensor_Value > 500))
{
float ReactSecs = float(reactionTime-raceStart) / 1000;
lcd.clear();
lcd.print(" GO ");
delay(500);
lcd.clear();
lcd.setCursor(1,0);
lcd.print("RT:");lcd.print(ReactSecs, 2);
Serial.print("RT:"); Serial.println(ReactSecs, 2);
state++;
}
break;
case 6: //racing
if (analogRead(Finish_Sensor) < 500)
{ if (!FinishFlag)
{ FinishFlag = true;
FinishET = millis() - vehicleStart;
lcd.clear();
lcd.print("ET:");
float secs = float(FinishET) / 1000;
lcd.print(secs);
lcd.setCursor(8,0);
float ReactSecs = float(reactionTime-raceStart) / 1000;
lcd.print("RT:");lcd.print(ReactSecs, 2);
lcd.setCursor(0, 1);
lcd.print("MPH:");
float fps = (TRACK_LEN / secs);
Serial.print("ET:"); Serial.println(secs, 2);
float mph = (fps / FEET_PER_MILE) / 0.00028;
Serial.print("MPH:"); Serial.println(mph, 2);
lcd.print(mph, 2);
state = 7;
}
} else FlipAni();
break;
case 7:
if (digitalRead(RESET_BTN) == LOW)
{
digitalWrite(LED_Start, LOW);
digitalWrite(LED_Stage, LOW);
digitalWrite(LED_RED_Light, LOW);
StartFlag = false;
FinishFlag = false;
state = 0;
}
break;
}
}// END LOOP BRACKETS
void FlipAni() {
if (millis() - AniMilli >= IntervalAni)
{
AniMilli = millis();
switch (flip) {
case 0: flip = 1; lcd.setCursor(0, 0); lcd.print("|"); lcd.setCursor(15, 0); lcd.print("|"); break;
case 1: flip = 2; lcd.setCursor(0, 0); lcd.print("/"); lcd.setCursor(15, 0); lcd.print("/"); break;
case 2: flip = 3; lcd.setCursor(0, 0); lcd.print("-"); lcd.setCursor(15, 0); lcd.print("-"); break;
case 3: flip = 4; lcd.setCursor(0, 0); lcd.print("\x01"); lcd.setCursor(15, 0); lcd.print("\x01"); break;
case 4: flip = 0; lcd.setCursor(0, 0); lcd.print("|"); lcd.setCursor(15, 0); lcd.print("|"); break;
}
}
}
(Working SIM Sample)
https://wokwi.com/projects/357668855954826241
-
Red light negative reaction to be added to the code to display how early they left before green.
-
Add second lane to the equation.
-
Add win light
-
Add win margin
-
Add Foul (Late Stage Equation) late stage for second vehicle to stage
-
Add dial in time option
-
Add breakout Foul (If vehicle runs faster than dial in time)
-
Add 3 Tree Configurations (STD, Pro, Hybrid)
-
ect. (Still More to Come)
Special thanks to everyone contributing to this code especially @qubits-us for all the extra of subject questions and small debugging issues I always encounter and then all of you in the form tread for always willing to help.
A little update all the reaction times are now working incredibly well thanx to @qubits-us
#include <LiquidCrystal.h>
#define FEET_PER_MILE 5280
#define TRACK_LEN 1320
#define RESET_BTN 47
const byte RS = 52;
const byte EN = 49;
const byte D4 = 53;
const byte D5 = 50;
const byte D6 = 51;
const byte D7 = 48;
const byte BAUD_RATE = 9600;
const byte LED_Prestage = 8;
const byte LED_Stage = 7;
const byte LED_Y1 = 6;
const byte LED_Y2 = 5;
const byte LED_Y3 = 4;
const byte LED_Start = 3;
const byte LED_RED_Light = 2;
const byte Pre_Stage_Sensor = A0;
const byte Stage_Sensor = A1;
const byte Finish_Sensor = A2;
const byte Start_Button = 46;
//how long is the countdown
const int CountDownFin = 2000;
//define missing slash char for Flip ani..
uint8_t slash[8] = {
0b10000,
0b10000,
0b01000,
0b00100,
0b00100,
0b00010,
0b00001,
0b00001,
};
byte flip = 0;
unsigned long AniMilli = 0;
int IntervalAni = 50;
int state = 0;
bool StartFlag = false;
unsigned long countdownStart;
unsigned long raceStart;
unsigned long reactionTime;
unsigned long vehicleStart;
bool FinishFlag;
unsigned long FinishET;
//float ReactSec;
int Pre_Stage_Sensor_Value;
int Stage_Sensor_Value;
int Finish_Sensor_Value;
bool Staged = false;
LiquidCrystal lcd(RS, EN, D4, D5, D6, D7);
void setup() {
pinMode(LED_Prestage, OUTPUT);
pinMode(LED_Stage, OUTPUT);
pinMode(LED_Y1, OUTPUT);
pinMode(LED_Y2, OUTPUT);
pinMode(LED_Y3, OUTPUT);
pinMode(LED_Start, OUTPUT);
pinMode(LED_RED_Light, OUTPUT);
pinMode(Pre_Stage_Sensor, INPUT);
pinMode(Stage_Sensor, INPUT);
pinMode(Finish_Sensor, INPUT);
pinMode(Start_Button, INPUT_PULLUP);
pinMode(RESET_BTN, INPUT_PULLUP);
//Serial.begin(BAUD_RATE);
Serial.begin(115200);
lcd.begin(16, 2);
lcd.createChar(1, slash);
lcd.setCursor(0, 1);
lcd.print(F("System Ready"));
delay(2000);
lcd.clear();
}
void loop()
{
//read in our sensors start of every loop..
//don't need anymore analogRead anywhere else but here..
Pre_Stage_Sensor_Value = analogRead(Pre_Stage_Sensor);
Stage_Sensor_Value = analogRead(Stage_Sensor);
Finish_Sensor_Value = analogRead (Finish_Sensor);
/*
Serial.print("PreStage: ");
Serial.println(Pre_Stage_Sensor_Value);
Serial.print("Stage: ");
Serial.println(Stage_Sensor_Value);
Serial.print("Finish: ");
Serial.println(Finish_Sensor_Value);
Serial.print("State: ");
Serial.println(state);
Serial.println();
delay(2000);
*/
//enter the state machine..
switch (state) {
case 0:
if (Pre_Stage_Sensor_Value > 500) {
digitalWrite(LED_Prestage, LOW);
}
else {
digitalWrite(LED_Prestage, HIGH);
state++;
}
break;
case 1:// Vehicle Staging State
if (Stage_Sensor_Value > 500) {
digitalWrite(LED_Stage, LOW);
}
else {
digitalWrite(LED_Stage, HIGH);
}
if (Stage_Sensor_Value < 500) {
lcd.clear();
lcd.print("Vehicle Ready");
delay(500);
state++;
}
else {
lcd.clear();
lcd.print("Please Stage");
delay(500);
state--;
}
break;
case 2: //check stage sensor and roll state back
if (Stage_Sensor_Value > 501) {
state--;
}
else
{ //staged good .. check start button
if (digitalRead(Start_Button) == LOW)
{
countdownStart = millis();
state++;
}
}
break;
case 3: //state 3 counts down leds and checks for early start..
//check for early start first..
if (!CheckEarlyStart()) {
//not an early start, countdown
if (millis() - countdownStart > 2000) //countdown done
{ //check sensor just before dropping the flag
digitalWrite(LED_Y3, LOW);
digitalWrite(LED_Start, HIGH);
StartFlag = true;
raceStart = millis();//start counting race from here..
state++;
}
else if (millis() - countdownStart > 1500)
{
digitalWrite(LED_Y2, LOW);
digitalWrite(LED_Y3, HIGH);
}
else if (millis() - countdownStart > 1000)
{
digitalWrite(LED_Y1, LOW);
digitalWrite(LED_Y2, HIGH);
}
else if (millis() - countdownStart > 500)
{
digitalWrite(LED_Y1, HIGH);
}
}
break;
case 4: //stage to get reaction time
//need to see car move before next state..
if (Stage_Sensor_Value > 500 && StartFlag)
{
vehicleStart = millis();
reactionTime = millis();
state++;
}
break;
case 5:
//prints go and reaction time..
{
float ReactSecs = float(reactionTime - raceStart) / 1000;
lcd.clear();
lcd.print(" GO ");
lcd.setCursor(0, 1);
lcd.print("RT:"); lcd.print(ReactSecs, 2);
Serial.print("RT:"); Serial.println(ReactSecs, 2);
state = 6;
}
break;
case 6:
if (Finish_Sensor_Value < 500)
{ if (!FinishFlag)
{ FinishFlag = true;
FinishET = millis() - vehicleStart;
lcd.clear();
lcd.print("ET:");
float secs = float(FinishET) / 1000;
lcd.print(secs);
lcd.setCursor(8, 0);
float ReactSecs = float(reactionTime - raceStart) / 1000;
lcd.print("RT:"); lcd.print(ReactSecs, 2);
lcd.setCursor(0, 1);
lcd.print("MPH:");
float fps = (TRACK_LEN / secs);
Serial.print("ET:"); Serial.println(secs, 2);
float mph = (fps / FEET_PER_MILE) / 0.00028;
Serial.print("MPH:"); Serial.println(mph, 2);
lcd.print(mph, 2);
state = 7;
} else FlipAni();
} else FlipAni();
break;
case 7:
if (digitalRead(RESET_BTN) == LOW)
{
digitalWrite(LED_Start, LOW);
digitalWrite(LED_Stage, LOW);
digitalWrite(LED_RED_Light, LOW);
StartFlag = false;
FinishFlag = false;
Staged = false;
state = 0;
}
break;
}
}// END LOOP BRACKETS
bool CheckEarlyStart()
{
bool early = false;
if (Stage_Sensor_Value > 501) {
reactionTime = CountDownFin - (millis() - countdownStart);
digitalWrite(LED_Y3, LOW);
digitalWrite(LED_Prestage, LOW);
digitalWrite(LED_Stage, LOW);
digitalWrite(LED_RED_Light, HIGH);
float ReactSecs = (float(reactionTime) / 1000) * -1;
lcd.clear();
lcd.print("!!Bad Start!!");
lcd.setCursor(0, 1);
lcd.print("RT:"); lcd.print(ReactSecs, 2);
Serial.print("RT:"); Serial.println(ReactSecs, 2);
state = 7;//bad start .. wait for reset..
early = true;
}
return early;
}
void FlipAni() {
if (millis() - AniMilli >= IntervalAni)
{
AniMilli = millis();
switch (flip) {
case 0: flip = 1; lcd.setCursor(0, 0); lcd.print("|"); lcd.setCursor(15, 0); lcd.print("|"); break;
case 1: flip = 2; lcd.setCursor(0, 0); lcd.print("/"); lcd.setCursor(15, 0); lcd.print("/"); break;
case 2: flip = 3; lcd.setCursor(0, 0); lcd.print("-"); lcd.setCursor(15, 0); lcd.print("-"); break;
case 3: flip = 4; lcd.setCursor(0, 0); lcd.print("\x01"); lcd.setCursor(15, 0); lcd.print("\x01"); break;
case 4: flip = 0; lcd.setCursor(0, 0); lcd.print("|"); lcd.setCursor(15, 0); lcd.print("|"); break;
}
}
}

V5 Reaction Time +&- Working - Wokwi Arduino and ESP32 Simulator
Run IoT and embedded projects in your browser: ESP32, Arduino, Pi Pico, and more. No installation required!
Next up I think the hardest part is still to come.
- Add second lane to the equation.
- Add win light
- Add win margin
- Add Foul (Late Stage Equation) late stage for second vehicle to stage
- Add dial in time option
- Add breakout Foul (If vehicle runs faster than dial in time)
- Add 3 Tree Configurations (STD, Pro, Hybrid)
- ect. (Still More to Come)
If anyone has ideas on where to begin for the second lane it would be highly appreciated.
Just to give you guys an update I have been running around trying new state cases ect ect ect to add the second lane and keep running into more and more issues what would you do to add the second lane ? trying to pick some brains & ideas but not getting anywhere so I thought I return here and see what you guys might think will work.
If you literally want two of something you have one of, a naive approach, which would work, is to cut, paste and edit that code to make it respond to its own inputs and keep track with its own variables.
This is OK, but gets old when you go to add a third or fourth lane…
So we steer you to learning about how to use functions, to have generalized algorithm that can handle any number of tracks, or whatever.
Which dovetail nicely with array variables so each track gets its own slot for storing its unique data.
Any time you have largely similar code blocks, you should think about writing a function.
Any time you are introducing variables that differ, say, only in an appended digit car1, car2, car3 and so forth, you should think about using arrays.
Have you learned about or used functions and arrays?
What have you tried so far? Post code that was your attempt, even if it doesn't compile or do, yet, what you want.
HTH
a7
Any luck? been considering this myself
Please don't necro an thread to ask a question like this. Either send the OP a private message if you only want information from them, or create a new thread, explaining your specific needs and goals, what you have done already, etc. and just include a reference link to this thread.
Yeah Id love to know what you found out. Thanks