For those wishing to duplicate this effort, can you post the code as well?
Sure thing. It's a bit of a mess, but it works, and I figure thats the important part.
/* Random Lap Trigger
By: JGL JohnGaltLine@comcast.net
Open Source distribution. */
int minimunLapsToTrigger = 10; // Set minimum number of laps before triggering.
int maximumLapsToTrigger = 25; // Set maximum number of laps before triggering.
int maximumActivationTimer = 15; // max on-time hold timer(seconds)
int inputPin = 9; // Arduino pin connected to input circuit.
int outputPin = 10; // Arduino pin connected to output relay module.
int debouncedCurrentInputState = 1; // stores current state of input pin, debounced.
int lastInputState = 0; // stores last state of input pin.
int lapCounter = 0; // stores count of number of times train has passed.
int numberOfLapsBeforeTriggering = 0; // stores random number of laps before triggering.
int currentInputState = 1; // stores current state of input pin, actual.
int debounceTime = 20; // debounce time (ms.).
unsigned long currentTime = 0; //Var for clock.
unsigned long debounceClockOne; // var for main input debounce.
unsigned long debounceClockTwo; // var for manual overide input debounce.
int manualOverideInputPin = 12; // manual button input pin.
int debouncedManualButton = 1; // var for manual overide, debounced
int manualButtonInputState = 1; // var for manual overide, pin state.
int outputOn = 0; // var for output state, not timed.
unsigned long activationTimer = 500; // clock for minimum run time.
int OutputLastState = 0; // var stores state of output on last cycle.
int activationTimerPotInputPin = A2; // input pin for setting timer.
int activationTimerPotInput = 0; // var to store analog value from pot
int minimumActivationTime = 0; // Var to set minimum on time bottom limit for pot. (ms)
void setup() {
// put your setup code here, to run once:
pinMode(inputPin, INPUT); // Set input pin as an input.
digitalWrite(inputPin, HIGH); // turn on internal pull-up resistor.
pinMode(manualOverideInputPin, INPUT); // Set input pin as an input.
digitalWrite(manualOverideInputPin, HIGH); // turn on internal pull-up resistor.
pinMode(activationTimerPotInput, INPUT); // set pin as input.
pinMode(outputPin, OUTPUT); // set output pin as an output
pinMode(A0, INPUT);
randomSeed(analogRead(A0)); // seed the random number generator with a floating value.
digitalWrite(outputPin, HIGH); // make sure the relay is turned off when device starts.
Serial.begin(9600); // initialize the serial port for debugging
}
void loop() {
// put your main code here, to run repeatedly:
currentTime = millis(); // set the clock variable to the current time.
activationTimerPotInput = analogRead(activationTimerPotInputPin); // read in the delay falue fro the pot.
minimumActivationTime = map(activationTimerPotInput, 0, 1023 , 0, (maximumActivationTimer * 1000)); // remap pot value to min/max settings.
// debounce for main input
if (currentTime >= debounceClockOne + debounceTime) {
currentInputState = digitalRead(inputPin); // read input value into var.
debounceClockOne = currentTime; //reset debounce clock.
debouncedCurrentInputState = currentInputState; // set debounced value.
}
// debounce for manual overide input
if (currentTime >= debounceClockTwo + debounceTime) {
manualButtonInputState = digitalRead(manualOverideInputPin); // read input value into var.
debounceClockTwo = currentTime; //reset debounce clock.
debouncedManualButton = manualButtonInputState; // set debounced value.
}
// if train is there, and it was not on last loop:
if (debouncedCurrentInputState == 0 && debouncedCurrentInputState != lastInputState) {
lapCounter++; // increase lap counter by 1
}
lastInputState = debouncedCurrentInputState; // set last state to current one for next loop.
if (lapCounter >= numberOfLapsBeforeTriggering && debouncedCurrentInputState == 0) { // if train is there and enough laps have passed:
outputOn = 1; // set output on. (not timed)
}
else if (debouncedManualButton == 0) { // or if the manual button is pressed
outputOn = 1; // set output on. (not timed)
}
else { // if not enough laps:
outputOn = 0; // set output off. (not timed)
}
// when train is past after activating:
if (lapCounter >= numberOfLapsBeforeTriggering && debouncedCurrentInputState == 1) {
lapCounter = 0; // reset the lap counter.
// set a new random number of laps for the next time.
numberOfLapsBeforeTriggering = random(minimunLapsToTrigger, maximumLapsToTrigger);
}
// detect when first tirggered and start timer.
if (outputOn == 1 && OutputLastState != outputOn) {
activationTimer = currentTime; // start minimum on time timer.
}
OutputLastState = outputOn; //reset value for next cycle's check.
if (outputOn == 1) { // if output is supposed to be on...
digitalWrite(outputPin, LOW); // turn on output (relay on.)
}
else if (outputOn == 0 && currentTime >= activationTimer + minimumActivationTime){ // if output is supposed to be off, and minimum time has passed...
digitalWrite(outputPin, HIGH); // turn off output (relay off)
}
// serial print for debug.
Serial.print("Track state: ");
Serial.print(debouncedCurrentInputState); // print state of main input.
Serial.print(" Manual state: ");
Serial.print(debouncedManualButton); // print state of manual input button.
Serial.print(" Laps for trigger: ");
Serial.print(numberOfLapsBeforeTriggering); // print random number generated for laps between triggering.
Serial.print(" Lap Count: ");
Serial.print(lapCounter); // print total laps counted since last trigger.
Serial.print(" Min Time: ");
Serial.print(minimumActivationTime); // print current setting of minimum activation time.
Serial.println(" ");
} // end main loop.
I think that it would be fairly easy to modify for various functions, removing the random number for a standard timed output track sensor, for example. Unfortunately feature creep makes things more complex. it would be dead simple if I could count on folks to be willing to download the Arduino IDE, and plug each board in to change a couple variables at the top of the program, but I don't see that as a marketable option, at least for most users of this forum. Adding a set of dip switches to allow people to change the functions is another option, but that would add bulk and complexity to the think, and even then might be too confusing for some folks. Before I think on it too much, I suppose it would be helpful to get a list of features that folks would like in a track sensor, then go from there to see what can be done easily, and what is best left undone. As another thought, it might be that I could keep each individual sensor as simple as possible, then build a 'programer' module that is used to set up the sensor for the feature that is wanted. Who knows at this point.
JGL