I'm using an IR LED and phototransistor I got from led-switch.com.
I got the system to work for detecting an entire train using the setup shown in the first pic. The secret was to make the beam (with this IR LED it hardly deserves being called a beam) at an angle to the train. That way it never sees a gap until the train has passed.
I ran into an interesting problem when it came to counting cars. At first I debugged the program using a business card and verified the logic was working, but when it came to the real train, it proved a lot harder to get it to work.
The problem is, unlike the detector for the whole train, there is no good way to position the detectors at the sides if you want to sense both cars and gaps with no chance of leakage. At first I placed them at the height of a flatcar and facing straight across the tracks. This failed miserably.
The reason is that there are too many differences between cars and even engines. The first problem was the engine. At the height of the flatcar, the beam can penetrate to the other side if an engine crosses because there are gaps at the fuel tank there. Even the handrails and coupler will cause false gap sensing, so raising and lowering the detectors to fix that, would then fail on the wide variety of other cars available.
So it seems I'd have to find an angle shooting up that would work that lets more of the car help block the signal. Going from the bottom of the track to a detector looking straight down might work too. If it comes to it I have a bridge I can test it on. For me reflection (having both devices side-by-side under the tracks) is out because it's too dependent on a consistent reflectivity.
The other issue is the short flickers that are caused by all these car differences. Sometimes I'll get 3 or 4 triggers because of the various little parts on each type of car. But I think I know a way to "debounce" this problem.
I finally got it all to work reliably. I have attached a pic of the physical setup. The code is posted below, as well as a copy of the debugging messages.
The key was to set up the detector at an angle, and to include a "toggle" routine. The toggle routine turns off the emmiter as soon as the first detection occurs. I leave the IR LED off for 35 mS, which is a little smaller time than an entire car takes to pass the detector at a very fast speed. Ideally I think the emitter should be below the track and the detector above the track (and train).
But. many of these IR LEDs are very poor directional devices. They are basically a flashlight sort of emmission. I included a pic of one shining onto some optical detection paper. You can see how large the beam is getting even at a short distance. However, I have on order some devices that will solve this problem - IR lasers. I got two of them for $9.99 each off of Ebay -
http://www.ebay.com/itm/110985868796?ss ... 1497.l2649
Using these I'll be able to shine it a long way down the track, or up close perhaps even count wheels. I'll have to adjust the output power up close so I don't burn out the phototransistor. I might have been able to use a red laser, but I don't want it to look like the Terminator is hunting down my trains.
Here's some results from the car counting experiments, but the code did work reliably as is, even thout it needs cleaned up a bit.
Debugging messages
These values were recorded for a "slow" train of 9 units
cars: 1 cartime: 2.00 gap time: 0.11
cars: 2 cartime: 1.59 gap time: 0.10
cars: 3 cartime: 1.53 gap time: 0.07
cars: 4 cartime: 1.66 gap time: 0.09
cars: 5 cartime: 1.80 gap time: 0.10
cars: 6 cartime: 1.72 gap time: 0.08
cars: 7 cartime: 1.70 gap time: 0.05
cars: 8 cartime: 1.61 gap time: 0.09
cars: 9 cartime: 2.13 EOT!!!
gap time: 3.00
These values are for a "fast" train of 9 units
cars: 1 cartime: 0.65 gap time: 0.02
cars: 2 cartime: 0.48 gap time: 0.00
cars: 3 cartime: 0.51 gap time: 0.01
cars: 4 cartime: 0.53 gap time: 0.01
cars: 5 cartime: 0.55 gap time: 0.01
cars: 6 cartime: 0.50 gap time: 0.01
cars: 7 cartime: 0.45 gap time: 0.01
cars: 8 cartime: 0.46 gap time: 0.01
cars: 9 cartime: 0.61 EOT!!!
gap time: 3.00
Code: Select all
/* This is a simple generic IR car/engine counting application shell.
//
// It uses a commonly available IR LED emmitter and IR sensing phototransistor.
// Available many places such as here http://www.led-switch.com/I.%20R.%20LED.htm
// Place the sensors at the angle you find that works on either side of the tracks.
//
// To use this to trigger another device add the device hardware and code to the Arduino.
//
*/
int irtx = 11; // digital pin 11 driving the IR LED
int irrx = A0; // analog pin A0 connected to the phototransistor
int active_car = 2; //digital pin 2, red LED
int cars = 0;
unsigned long time_hack;
boolean EOT = LOW; // End of Train signal
float gap_time;
float car_time = 0.0;
const float gap_limit = 3.0;
// gap_limit in seconds is the max limit for a unit gap. Set this to suit your needs.
// If this limit is exceeded it signals the EOT
void setup()
{
pinMode(irtx, OUTPUT);
pinMode(active_car, OUTPUT);
digitalWrite(irtx,HIGH); //turn on IR LED
Serial.begin(9600);
}
void loop()
{
digitalWrite(active_car,LOW);
EOT = LOW;
cars = 0;
while((.0049 * analogRead(A0)) < 4.3)
{
//wait for 1st unit trigger
}
ir_toggle();
while (EOT == LOW)
{
digitalWrite(active_car,HIGH);
time_hack = millis(); //get a time hack
while ((.0049 * analogRead(A0)) > 4.3)
{
//wait till the car passes
}
ir_toggle();
car_time = float((millis() - time_hack)) / 1000.0; // compute car passing time
cars++;
Serial.print(" cars: ");
Serial.print(cars);
Serial.print(" cartime: ");
Serial.print(car_time);
digitalWrite(active_car,LOW);
time_hack = millis(); //get a time hack
while (((.0049 * analogRead(A0)) < 4.3) && (EOT == LOW)) //wait for the gap or the EOT
{
gap_time = float((millis() - time_hack)) / 1000.0;
if (gap_time >= gap_limit)
{
EOT = HIGH;
Serial.println(" EOT!!!");
}
}
ir_toggle();
Serial.print(" gap time: ");
Serial.println(gap_time);
}
delay(2000); //A little EOT saftey delay
}
void ir_toggle()
{
// this routine will shut off the IR emmission to prevent false triggers
digitalWrite(irtx,LOW);
delay(35);
//this value is slightly less than the minimum cartime recorded for a "fast" train
//this will shut off the IR LED for 35 mS
digitalWrite(irtx,HIGH);
}