This post contains supplemental information for my YouTube video titled “Model Railroad Speedometer Arduino Circuit – Part 1”
My project is based off initial work by Steve Spence on his YouTube channel:
https://www.youtube.com/user/sspence65
Here is a diagram of the circuit:
I have done a full re-write of the Arduino code to include the following features:
- scale speed is calculated in O-scale
- speed can be detected in either direction
- circuit will not “reset” based solely on time while a train is still triggering one or both sensors
Here is my Arduino code:
/*
Model Railroad Speedometer
-------------------------------------------
Bobot's Trains and Maker Zone
https://www.youtube.com/user/BobotsTrains
03/11/2017
Complete code re-write adding detection
in both directions and continuous train
length detection of before reset
-------------------------------------------
-------------------------------------------
Original concept by:
Steve Spence
https://www.youtube.com/user/sspence65
-------------------------------------------
*/
#include "Wire.h"
#include "Adafruit_LEDBackpack.h"
#include "Adafruit_GFX.h"
Adafruit_7segment matrix = Adafruit_7segment();
//user variables
float distance = 18; //distance between sensors (inches)
int scale = 48; //scale of model to report scale speed (O-Scale = 48)
int sensor1 = 4; //sensor1 digital pin
int sensor2 = 5; //sensor2 digital pin
int s1Open = 1; //is START sensor open/uncovered? (goes to 0 if covered/triggered)
int s2Open = 1; //is END sensor open/uncovered? (goes to 0 if covered/triggered)
float startmillis, finishmillis, elapsed, miles, hours, mph, scaleMPH;
bool started1 = false; // set to TRUE if START sensor has been triggered
bool started2 = false; // set to TRUE if END sensor has been triggered
bool initialized = true; //set to TRUE once all sensors are cleared for a period of time and ready to read
float previousmillis;
void setup() {
//Serial.begin(9600);
pinMode(sensor1, INPUT);
pinMode(sensor2, INPUT);
matrix.begin(0x70);
matrix.setBrightness(12);
matrix.print(0.0); //clear display to show 0
matrix.writeDisplay();
}
void loop() {
//read respective sensor if not already triggered
if (!started1) {s1Open=digitalRead(sensor1);}
if (!started2) {s2Open=digitalRead(sensor2);}
// if neither sensor previously triggered and both sensors currently uncovered and several seconds have passed
// determine if we can "reset" all variables and set the display to "8888"
if ((!started1 && !started2) && (s1Open && s2Open) && ((millis() - previousmillis > 5000))) {
bool goodtogo = true;
float starttesttime = millis();
// assure no sensor triggers for several seconds before even attempting "reset"
while ((millis() - starttesttime) < 5000) {
if (!digitalRead(sensor1) || !digitalRead(sensor2)) {
goodtogo = false;
break;
}
}
// neither sensor was previously triggered, nor triggered in last several seconds, so "reset"/initialize vars and display
if (goodtogo) {
initialized = true;
started1 = false;
started2 = false;
previousmillis = millis();
matrix.print(8888); //clear display to show 8888
matrix.writeDisplay();
}
}
// Sensor 1 is triggered, neither sensor was previously triggered, and we were in initialize mode
if ((!s1Open) && (!started1 && !started2) && (initialized)) {
started1 = true;
initialized = false;
startmillis = millis();
}
// Sensor 2 is triggered, neither sensor was previously triggered, and we were in initialize mode
if ((!s2Open) && (!started1 && !started2) && (initialized)) {
started2 = true;
initialized = false;
startmillis = millis();
}
//a first sensor (START) was previously triggered and now a second sensor (END) is triggered, calculate and display scale MPH
if (((started1) && (!s2Open)) || ((started2) && (!s1Open))) {
finishmillis=millis();
//Serial.println("Finished");
elapsed = finishmillis-startmillis;
elapsed = elapsed / 1000; //seconds
//Serial.print("Seconds: ");
//Serial.println(elapsed);
miles = distance / 63360; //miles
hours = elapsed / 3600; //hours
mph = miles / hours;
scaleMPH = mph * scale;
//Serial.print("Scale MPH: ");
//Serial.println(scaleMPH);
//slow blink if between 50 and 69 scale MPH
//fast blink if over 70 scale MPH
if ((scaleMPH >= 50) && (scaleMPH < 70)) {
matrix.blinkRate(3);
} else if (scaleMPH >= 70) {
matrix.blinkRate(1);
}
// print scale MPH on display
matrix.print(scaleMPH);
matrix.writeDisplay();
// reset
delay(5000); //wait
matrix.blinkRate(0);
matrix.print(0.0); //clear display to show 0
matrix.writeDisplay();
started1 = false;
started2 = false;
}
}