Reading Two Sensors

How fast is the train moving? What scale? Are you sure 100ms is long enough? Can the light be a half second or a second behind? Can we try a longer debounce?

PilotinControl: I hope that clears up any confusion on what I am trying to accomplish.

howabout posting a drawing of where the tracks cross and where the sensors are?

@BulldogLowell - Drawing was posted in an above message @aarg - That would be a feasable idea as something I was trying to accomplish with using 2 sensors at each end of the block @Delta_G - The scale is HO Scale, the speed will vary and 100 ms I was just using as an example.

Now....when the whole train crosses a sensor not each car... that should start a time for how long the red stays on....keeps counting until it reaches the second sensor which would stop the time and turn the signals green and the same would be true going in the opposite direction. Debouncing the sensor is the key....each time there is a space between the cars it re-triggers the sensor so the timing starts over again which we do not want. IR beam breaks once...with the first locomotive or car.

Actually, in the scheme I put forth, debouncing is not necessary. Not that it is necessarily the scheme that you need...

PilotinControl: Debouncing the sensor is the key....each time there is a space between the cars it re-triggers the sensor so the timing starts over again which we do not want. IR beam breaks once...with the first locomotive or car.

I think your paradigm is a bit troublesome...

Just keep the sensors "Sensing" (sensors gotta sense after all) and react accordingly. A state machine type of approach is then a lot easier.

I outlined what I mean in the following code... Take a look and see if you understand. I assumed train coming from the right, but if not, all you have to do is reverse the pins and/or turn your diagram over! ;)

enum CrossingState{
  CLEAR,
  APPROACHING,
  EXITING,
};

const uint32_t SOME_TIME_IN_MILLIS = 2000; // 2 seconds
const byte rightSensor = 5;
const byte leftSensor = 4;
CrossingState ElmStreetCrossing = CLEAR;

void setup() 
{
  Serial.begin(9600);
  Serial.println(F("Let's Go!"));
  pinMode(rightSensor, INPUT);
  pinMode(leftSensor, INPUT);
}

void loop() 
{
  static uint32_t rightSensorMillis = 0;
  static uint32_t leftSensorMillis = 0;
  
  int rightSensorState = digitalRead(rightSensor);
  if (rightSensorState)
  {
    rightSensorMillis = millis();
  }
  
  int leftSensorState = digitalRead(leftSensor);
  if (leftSensorState)
  {
    leftSensorMillis = millis();
  }

  switch (ElmStreetCrossing)
  {
    case CLEAR:
      if(rightSensorState)
      {
        trainApproaching();
        ElmStreetCrossing == APPROACHING;
        Serial.println(F("Train Approaching"));
      }
      break;
    case APPROACHING:  // stay in this state until train comes to 2nd sensor
      if (leftSensorState)
      {
        ElmStreetCrossing = EXITING;
      }
      break;
    case EXITING:  // stay in this state until train clears 2nd sensor
      if (millis() - leftSensorMillis > SOME_TIME_IN_MILLIS /*and millis() - rightSensorMillis > SOME_TIME_IN_MILLIS*/)  // you can uncomment in the case where it is possibl that a train is following
      {
        trainDeparted();
        ElmStreetCrossing = CLEAR;
        Serial.println(F("Train CLEAR"));
      }
      break;
  }
}

void trainDeparted(){}
void trainApproaching(){}

@BulldogLowell - Thanks for your post however once loaded to the arduino the Red LED lights up right away. As the code stands the sensors are HIGH/LOW. In other words: Each sensor is in a HIGH State until something crosses it and then it goes to a LOW state. I added if (rightSensorState == LOW) as well as if (leftSensorState == LOW) which only half worked...as in when the second sensor was crossed it did not invoke the Exit/Clear state.

Added how?

@BulldogLowell - Here is where I added it. Unless that is the wrong place:

if(rightSensorState == LOW) {
trainApproaching();
ElmStreetCrossing == APPROACHING;
Serial.println(F("Train Approaching"));
}
break;
case APPROACHING:  // stay in this state until train comes to 2nd sensor
if (leftSensorState == LOW) {
ElmStreetCrossing = EXITING;
Serial.println(F("Train Departing"));
}

These are TCRT5000 IR reflective sensors. Default state is HIGH....LOW is when something is sensed.

What I want to avoid is the flickering of the LED. IR Beam broken once RED on and stays on....time starts...however this should not be a timer as when the time is up the LED goes back to the previous state....LEDS only change when a sensor is triggered. once the next sensor is tripped the time stops and LED goes to GREEN and vice versa no matter which sensor is triggered it could be the same sensor that was crossed. I know this is achievable and we are getting very close. Thanks for the help so far.

PilotinControl: @BulldogLowell - Here is where I added it. Unless that is the wrong place:

if(rightSensorState == LOW) {
trainApproaching();
ElmStreetCrossing == APPROACHING;
Serial.println(F("Train Approaching"));
}
break;
case APPROACHING:  // stay in this state until train comes to 2nd sensor
if (leftSensorState == LOW) {
ElmStreetCrossing = EXITING;
Serial.println(F("Train Departing"));
}

since LOW is active, so that the rest of the logic flow is normal, I'd just do it like this:

enum CrossingState{
  CLEAR,
  APPROACHING,
  EXITING,
};

const uint32_t SOME_TIME_IN_MILLIS = 2000; // 2 seconds
const byte rightSensor = 5;
const byte leftSensor = 4;
CrossingState ElmStreetCrossing = CLEAR;

void setup() 
{
  Serial.begin(9600);
  Serial.println(F("Let's Go!"));
  pinMode(rightSensor, INPUT);
  pinMode(leftSensor, INPUT);
}

void loop() 
{
  static uint32_t rightSensorMillis = 0;
  static uint32_t leftSensorMillis = 0;
  
  const bool rightSensorState = digitalRead(rightSensor) == LOW? true: false;
  if (rightSensorState)
  {
    rightSensorMillis = millis();
  }
  
  const bool leftSensorState = digitalRead(leftSensor) == LOW? true: false;
  if (leftSensorState)
  {
    leftSensorMillis = millis();
  }

  switch (ElmStreetCrossing)
  {
    case CLEAR:
      if(rightSensorState)
      {
        trainApproaching();
        ElmStreetCrossing == APPROACHING;
        Serial.println(F("Train Approaching"));
      }
      break;
    case APPROACHING:  // stay in this state until train comes to 2nd sensor
      if (leftSensorState)
      {
        ElmStreetCrossing = EXITING;
      }
      break;
    case EXITING:  // stay in this state until train clears 2nd sensor
      if (millis() - leftSensorMillis > SOME_TIME_IN_MILLIS /*and millis() - rightSensorMillis > SOME_TIME_IN_MILLIS*/)  // you can uncomment in the case where it is possibl that a train is following
      {
        trainDeparted();
        ElmStreetCrossing = CLEAR;
        Serial.println(F("Train CLEAR"));
      }
      break;
  }
}

void trainDeparted(){}
void trainApproaching(){}

PilotinControl: What I want to avoid is the flickering of the LED. IR Beam broken once RED on and stays on....time starts...however this should not be a timer as when the time is up the LED goes back to the previous state....LEDS only change when a sensor is triggered. once the next sensor is tripped the time stops and LED goes to GREEN and vice versa no matter which sensor is triggered it could be the same sensor that was crossed. I know this is achievable and we are getting very close. Thanks for the help so far.

that's some run-on sentence...

as the train approaches the crossing either of the two sensors may be triggered (i.e. the train can travel in either direction past the crossing?)

the traffic signal switches to red when the first sensor is tripped. that one is obvious so that puts us into APPROACHING state.

the signal returns to green when 1) once there is no longer presence detected on the 2nd sensor (plus some small amount of time) or 2) once the train crosses the 2nd sensor?

@BulldogLowell - Ok I tried the new code and the red triggers however once second sensor has been triggered there is no change of state: Led does not change from Red back to Green. I tried siwtching the order of sensors and the same behavior occurs.

Here is how it should work:

1.) Train passes first sensor - LED Goes Red and stays red until 2.) passing over 2nd sensor LED Goes Green. The same is true if 3.) 2nd sensor is triggered first and then 4.) 1st sensor is crossed LED goes from Red back to Green.

Here is the caveat on both instances.....There is a time when both sensors will NOT be covered as the train maybe shorter than the distance between the 2 sensors. This is why the LED has to stay Red until another sensor is passed over.

And to throw another instance in the mix: if sensor 1 is crossed...the train can stop...and reverse direction without triggering the 2nd sensor instead it crosses the 1st sensor again.

This is what we call Bi-Directional signalling.

That is why current based track block detection is hands down better. It is insensitive to direction, speed, and easily resolves a train spanning multiple blocks.

Remember that the signalled direction is either fixed, or remotely set by the traffic controller. The train direction itself should have no influence over it.

PilotinControl: And to throw another instance in the mix: if sensor 1 is crossed...the train can stop...and reverse direction without triggering the 2nd sensor instead it crosses the 1st sensor again.

Well, then I've certainly given you the framework to be able to add states (if necessary) and shown you how to change the states based on sensor indicators.

I guess you have to sit down with pencil and paper and look at all of the states you need to identify and all of the consequences of the changing sensor data whilst you are in each of those states.

@aarg - yes that is true and I have done current based detection using both Direct Current and DCC ( Digital command control) effectively using an arduino. I wanted to prove that using IR sensors can do the same thing. Original plan...and still maybe the most effective....is using 2 sensors at the beginning and entrance of the block.

Sorry for join this old thread but i have a similar question...

I have a module go tcrt5000 and I need that when I notice any movement activates the left mouse button, could you lend me a hand and I pay it to you ?? I have the sensor code but it is missing that when I get the movement press a key