IR Sensor operation

Hi John,

if my impression is wrong I apologise for misinterpreting it. You seem to be in a state of
"I'm almost there - I just need to code "X" and them I'm done" Where X is a small but relevant change to you code.

it is still not all clear to me. And for clarification a more detailed description is needed. I could do a rough estimation you mean it this or that way and still could be wrong with the coded solution. It might be that there are different cases throgh different lengths of the train which might cause de-railing if a bad combination of factors occur.

I guess your last description posted while I was writing my post clears up most of it.
From reading this I'm even more convinced that a statemachine is the way to go

And all these things have to be considered for a good and reliable working solution.
I have made a rough drawing that shows my understanding of your project. Please look at this drawing if my understanding is correct. If not make a similar drawing that shows how it really is. This drawing shall give you an example of how things can be cleared up by a "quick and dirty" hand-drawing. Only the principles have to be recognisable.

The basic principle is

1.) to analyse which sensor has witch state (LOW or HIGH) in which situation
2.) is there a fixed sequence of sensor-state-changes (IR1 goes from HIGH to LOW and stays LOW until ... etc. etc. etc.)

This may afford more drawings than I have done so far if there are a lot of variables like different train-lengths, etc.

Most users here would shout a "Hooray! finally a single user that posts sufficient hand drawn pictures of all states that could happen Very interesting combination of factors very intriguing challenge to write the code to solve this control-problem!"

If my understanding of the situation is 80% correct a statemachine will fulfill all your dreams how to control it. And once you have understood the basic principle of statemachines you can write code that everybody drops the jaw on the floor about what wild things go on on your modelrailway precise as a clockwork never crashing anything.

So give it a try to draw a corrected picture. And give it a try to understand how statemachines work.
If your situation is clear to us other users we will support you to get it going.

best regards Stefan
any newbee can apply the most professional habit from the first line of code they write on their own:
add only ONE thing at a time. Test/debug that ONE thing until that ONE thing works reliable - repeat.
The sad thing is: only the REAL professionals write code this way.

John40131:
My problem is I am a novice at sketch programs and can easily get in a hole and I dont know what I did wrong ... as it is at the moment all works apart from this Sensor Exit issue ...

people keep telling me to learn but this is a not quite one off as I do have other Arduino modules within my layout but I have other things to make on this Model Railway and I have spent 18 months and layout is not yet up and running and that is not an Arduino problem its just time and being nearly 73 its not easy to learn code ..

Here is a simple sketch using the states I outlined and your IR sensors. I made up the pin numbers and I assume I understand what you are trying to accomplish. Either way, it gives you an idea of how to monitor the sensors and how to translate the state machines into code. I could have written the code more efficiently but I chose readability over efficiency. It compiles but I do not have the hardware to test it:

const int irSensor1Pin = 3;
const int irSensor2Pin = 4;
const int signalButtonPin = 5;
const int senseLed1Pin = 6;


enum _train_state_enum
{
  NOT_IN_BLOCK,
  IN_BLOCK,
  EXITING_BLOCK
};

_train_state_enum trainState = NOT_IN_BLOCK;


void setup() 
{
  Serial.begin(115200);
  pinMode (irSensor1Pin, INPUT);
  pinMode (irSensor2Pin, INPUT);
  pinMode (signalButtonPin, INPUT_PULLUP);
  pinMode (senseLed1Pin, OUTPUT);
  
  // TBD: You may want to perform some checks here in case the train is already in the block during initialization
}

void loop()
{
  bool irSensor1Triggered = checkIrSensor1Triggered();
  bool irSensor2Triggered = checkIrSensor2Triggered();
  bool irSensor2Released = checkIrSensor2Released();
  
  switch (trainState)
  {
    case NOT_IN_BLOCK:
      if (irSensor1Triggered)
      {
        // Sensor 1 was triggered so the train has entered the block
        
        // TBD: Perform any one-time actions necessary before entering the IN_BLOCK state.
        digitalWrite(senseLed1Pin, HIGH);
        trainState = IN_BLOCK;
      }
      break;
      
    case IN_BLOCK:
      // TBD: perform actions here that need to be done continuously during the IN_BLOCK state
      if (irSensor2Triggered)
      {
        // Sensor 2 has triggered so the train is exiting the block but is still in the block
        
        // TBD: Perform any one-time actions necessary before entering the EXITING_BLOCK state.
        trainState = EXITING_BLOCK;
      }
      break;
      
    case EXITING_BLOCK:
      // TBD: perform actions here that need to be done continuously during the IN_BLOCK state
      if (irSensor2Released)
      {
        // Sensor 2 has released so the train has exited the block
        
        // TBD: Perform any one-time actions necessary before entering the NOT_IN_BLOCK state.
        digitalWrite(senseLed1Pin, LOW);
        trainState = NOT_IN_BLOCK;
      }
      break;

    default:
      // ****** SHOULD NEVER GET HERE !!!!!!!!
      Serial.println("ERROR: Invalid Train State");
      trainState = NOT_IN_BLOCK;
  }
}

bool checkIrSensor1Triggered()
{
  // This function returns true if the sensor state transitioned from
  // HIGH to LOW
  static byte lastSensorState = digitalRead(irSensor1Pin);
  bool triggered = false;
  
  // read the sensor input pin:
  byte sensorState = digitalRead(irSensor1Pin);

  // compare the buttonState to its previous state
  if (sensorState != lastSensorState) 
  {
    if (sensorState == LOW) triggered = true;
    delay(50); // debounce (probably not needed)
    lastSensorState = sensorState;
  }
  return triggered;
}

bool checkIrSensor2Triggered()
{
  // This function returns true if the sensor state transitioned from
  // HIGH to LOW
  static byte lastSensorState = digitalRead(irSensor2Pin);
  bool triggered = false;
  
  // read the sensor input pin:
  byte sensorState = digitalRead(irSensor2Pin);

  // compare the buttonState to its previous state
  if (sensorState != lastSensorState) 
  {
    if (sensorState == LOW) triggered = true;
    delay(50); // debounce (probably not needed)
    lastSensorState = sensorState;
  }

  return triggered;
}

bool checkIrSensor2Released()
{
  // This function returns true if the sensor state transitioned from
  // LOW to HIGH
  static byte lastSensorState = digitalRead(irSensor2Pin);
  bool released = false;
  
  // read the sensor input pin:
  byte sensorState = digitalRead(irSensor2Pin);

  // compare the buttonState to its previous state
  if (sensorState != lastSensorState) 
  {
    if (sensorState == HIGH) released = true;
    delay(50); // debounce (probably not needed)
    lastSensorState = sensorState;
  }

  return released;
}

OK I donwloaded your last posted code. For a real understanding it is important to know which sensorstate is sensing what and which button activates what

it is a common way seen by newbees to name inputs

sensorState1 = digitalRead(sensePin1);
 sensorState2 = digitalRead(sensePin2);
 sensorState3 = digitalRead(sensePin3);
 sensorState4 = digitalRead(sensePin4);
 sensorState5 = digitalRead(sensePin5);
 sensorState6 = digitalRead(sensePin6);
 sensorState7 = digitalRead(sensePin7);
 sensorState8 = digitalRead(sensePin8);

and buttons

   Buttonval1 = digitalRead(PushButton1);// Read the Button 1
   Buttonval2 = digitalRead(PushButton2);// Read the Button 2
   Buttonval3 = digitalRead(PushButton3);// Read the Button 3
   Buttonval4 = digitalRead(PushButton4);// Read the Button 4

To me I have no clue at all what button1,2,3,4 are doing.
For you it will be uch easier to maintain your code if you give everything a selfexplaining name.

As an example

 sensorState1 = digitalRead(sensePin1);

I guess this is IR-sensor1 from your description above
So a selfexplaining name could be "IRSensorAtBegin"

This means you code would change from

  int sensePin1 = 22; //Entry On Fast Up Line .. Exit Sensor Sen5 or 6

to

  int IRSensorAtBegin = 22; // no more comment needed comment is inside the name itself

from

from

   if (sensorState1 == LOW) {   // Start of Sensor 1 detection
   Serial.println(" Sensor State 1 ");//Reading IR Sensor 1
   
   digitalWrite (senseLed1, LOW);// Turns Mimic panel Sense 1 LED ON
   Serial.println(" Sense LED 1   ");

   Serial.print(senseLed1);
  }

to

   if (IRSensorAtBeginState  == LOW) {   
   Serial.println(" IRSensorAtBegin == LOW ");
   
   digitalWrite (LED_EnteringBlock1, LOW);
   Serial.println(" LED_EnteringBlock1 is ON   ");
  }

This will it make much easier to maintain your code in half a year. because the code explains itself
You don't have to remember what was sensorState4 This ? .... or that???

Take time to think about a good selfexplaining name not to long but stating everything important
Then you can modify your code with find and replace very quickly

best regards Stefan
any newbee can apply the most professional habit from the first line of code they write on their own:
add only ONE thing at a time. Test/debug that ONE thing until that ONE thing works reliable - repeat.
The sad thing is: only the REAL professionals write code this way.

StefanL38:
Hi John,

if my impression is wrong I apologise for misinterpreting it. You seem to be in a state of
"I'm almost there - I just need to code "X" and them I'm done" Where X is a small but relevant change to you code.

it is still not all clear to me. And for clarification a more detailed description is needed. I could do a rough estimation you mean it this or that way and still could be wrong with the coded solution. It might be that there are different cases throgh different lengths of the train which might cause de-railing if a bad combination of factors occur.

I guess your last description posted while I was writing my post clears up most of it.
From reading this I'm even more convinced that a statemachine is the way to go

And all these things have to be considered for a good and reliable working solution.
I have made a rough drawing that shows my understanding of your project. Please look at this drawing if my understanding is correct. If not make a similar drawing that shows how it really is. This drawing shall give you an example of how things can be cleared up by a "quick and dirty" hand-drawing. Only the principles have to be recognisable.

The basic principle is

1.) to analyse which sensor has witch state (LOW or HIGH) in which situation
2.) is there a fixed sequence of sensor-state-changes (IR1 goes from HIGH to LOW and stays LOW until ... etc. etc. etc.)

This may afford more drawings than I have done so far if there are a lot of variables like different train-lengths, etc.

Most users here would shout a "Hooray! finally a single user that posts sufficient hand drawn pictures of all states that could happen Very interesting combination of factors very intriguing challenge to write the code to solve this control-problem!"

If my understanding of the situation is 80% correct a statemachine will fulfill all your dreams how to control it. And once you have understood the basic principle of statemachines you can write code that everybody drops the jaw on the floor about what wild things go on on your modelrailway precise as a clockwork never crashing anything.

So give it a try to draw a corrected picture. And give it a try to understand how statemachines work.
If your situation is clear to us other users we will support you to get it going.

best regards Stefan
any newbee can apply the most professional habit from the first line of code they write on their own:
add only ONE thing at a time. Test/debug that ONE thing until that ONE thing works reliable - repeat.
The sad thing is: only the REAL professionals write code this way.

Hi, Your drawing is correct and everything at the moment works like that ... i.e this sketch works fine ... BUT ... the issue is when you look at your drawing C ) when train hits IR2 it changes Signal and Point Servos and because the rest of the train is still crossing the points they will change in my sketch and will de-Rail the train ... and I want them to NOT change till all of train passes IR2 ... So goes HIGH ... so if I can get IR2 to do 2 operations that would be great ..

IR2 sensor operation

1st Operation just to change the signal back to RED.. High to Low when train hits it
2nd Operation change point servo's when ... Low to High when last carraige passes

ToddL1962:
Here is a simple sketch using the states I outlined and your IR sensors. I made up the pin numbers and I assume I understand what you are trying to accomplish. Either way, it gives you an idea of how to monitor the sensors and how to translate the state machines into code. I could have written the code more efficiently but I chose readability over efficiency. It compiles but I do not have the hardware to test it:

const int irSensor1Pin = 3;

const int irSensor2Pin = 4;
const int signalButtonPin = 5;
const int senseLed1Pin = 6;

enum _train_state_enum
{
  NOT_IN_BLOCK,
  IN_BLOCK,
  EXITING_BLOCK
};

_train_state_enum trainState = NOT_IN_BLOCK;

void setup()
{
  Serial.begin(115200);
  pinMode (irSensor1Pin, INPUT);
  pinMode (irSensor2Pin, INPUT);
  pinMode (signalButtonPin, INPUT_PULLUP);
  pinMode (senseLed1Pin, OUTPUT);
 
  // TBD: You may want to perform some checks here in case the train is already in the block during initialization
}

void loop()
{
  bool irSensor1Triggered = checkIrSensor1Triggered();
  bool irSensor2Triggered = checkIrSensor2Triggered();
  bool irSensor2Released = checkIrSensor2Released();
 
  switch (trainState)
  {
    case NOT_IN_BLOCK:
      if (irSensor1Triggered)
      {
        // Sensor 1 was triggered so the train has entered the block
       
        // TBD: Perform any one-time actions necessary before entering the IN_BLOCK state.
        digitalWrite(senseLed1Pin, HIGH);
        trainState = IN_BLOCK;
      }
      break;
     
    case IN_BLOCK:
      // TBD: perform actions here that need to be done continuously during the IN_BLOCK state
      if (irSensor2Triggered)
      {
        // Sensor 2 has triggered so the train is exiting the block but is still in the block
       
        // TBD: Perform any one-time actions necessary before entering the EXITING_BLOCK state.
        trainState = EXITING_BLOCK;
      }
      break;
     
    case EXITING_BLOCK:
      // TBD: perform actions here that need to be done continuously during the IN_BLOCK state
      if (irSensor2Released)
      {
        // Sensor 2 has released so the train has exited the block
       
        // TBD: Perform any one-time actions necessary before entering the NOT_IN_BLOCK state.
        digitalWrite(senseLed1Pin, LOW);
        trainState = NOT_IN_BLOCK;
      }
      break;

default:
      // ****** SHOULD NEVER GET HERE !!!!!!!!
      Serial.println("ERROR: Invalid Train State");
      trainState = NOT_IN_BLOCK;
  }
}

bool checkIrSensor1Triggered()
{
  // This function returns true if the sensor state transitioned from
  // HIGH to LOW
  static byte lastSensorState = digitalRead(irSensor1Pin);
  bool triggered = false;
 
  // read the sensor input pin:
  byte sensorState = digitalRead(irSensor1Pin);

// compare the buttonState to its previous state
  if (sensorState != lastSensorState)
  {
    if (sensorState == LOW) triggered = true;
    delay(50); // debounce (probably not needed)
    lastSensorState = sensorState;
  }
  return triggered;
}

bool checkIrSensor2Triggered()
{
  // This function returns true if the sensor state transitioned from
  // HIGH to LOW
  static byte lastSensorState = digitalRead(irSensor2Pin);
  bool triggered = false;
 
  // read the sensor input pin:
  byte sensorState = digitalRead(irSensor2Pin);

// compare the buttonState to its previous state
  if (sensorState != lastSensorState)
  {
    if (sensorState == LOW) triggered = true;
    delay(50); // debounce (probably not needed)
    lastSensorState = sensorState;
  }

return triggered;
}

bool checkIrSensor2Released()
{
  // This function returns true if the sensor state transitioned from
  // LOW to HIGH
  static byte lastSensorState = digitalRead(irSensor2Pin);
  bool released = false;
 
  // read the sensor input pin:
  byte sensorState = digitalRead(irSensor2Pin);

// compare the buttonState to its previous state
  if (sensorState != lastSensorState)
  {
    if (sensorState == HIGH) released = true;
    delay(50); // debounce (probably not needed)
    lastSensorState = sensorState;
  }

return released;
}

Thank you all for suggestions ...not sure were everyone lives but im in UK and its 19.30 know so another go tomorrow ...

And I will try your sketch with another Uno I have ...

Thank you I am most grateful for help..

John

Thanks again for help most grateful...

This is my breadboard build... the Red LED's are the signals and the Blue LEDs simulate the points and the position of everything is roughly track layout .. the Yellow LED's (you can only see one middle front) are telling me train hit IR sensor..

the statemachine will solve it with some mote states

enum _train_state_enum

  NOT_IN_BLOCK,
  IN_BLOCK,
  FIRST_WAGON_HAS_PASSED_IR2
  LAST_WAGON_HAS_PASSED_IR2
};

the basic principle of a statemachine is to execute parts of code only if they are needed

This is done by some kind of a mutliple but mutual-exclusive if-condition which is called switch-case

when train is outside block execute code "below" code-section NOT_IN_BLOCK
when train is inside block execute code "below" code-section IN_BLOCK
when the first wagon has passed IR2 execute code "below" code-section FIRST_WAGON_HAS_PASSED_IR2
which will just switch LEDs back to red
and will check if IR2 is HIGH
if IR2 has become HIGH execute code below "code-section" LAST_WAGON_HAS_PASSED_IR2
which will drive signs back to the other position

best regards Stefan
any newbee can apply the most professional habit from the first line of code they write on their own:
add only ONE thing at a time. Test/debug that ONE thing until that ONE thing works reliable - repeat.
The sad thing is: only the REAL professionals write code this way.

I will try your sketch shortly ... and yes if that is what you mean by statemachine or switch case ... I think this is something I have seen before on a sketch that I got off internet and a sketch that someone did for me but I couldnt work out how to construct it ...

But yes I think that is what I have to do so each operateion is split into seperate loops..

Not had chance to check as not feeling 100% today ... But this came up on the MERG forum that I am a nember of ...

Arduino Simulator