Pages: [1] 2   Go Down
Author Topic: Model Railway Level Crossing  (Read 2776 times)
0 Members and 1 Guest are viewing this topic.
Australia
Offline Offline
Newbie
*
Karma: 0
Posts: 26
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi Everyone.

I'm new to the world of programming and have bought myself an Arduino UNO. So far I have done pretty good on my own (with a little help from a friend) but I am having trouble.

What I want to do is build a fully functional Level Crossing for my model railway layout.

At the moment once the testing button is pressed it runs through once but I want to have the train trip a miniature reed switch hidden under the track on one side or the crossing which will then set off the flashing lights and lower the boom gates (which will be done with hobby servos) and then on the other side of the crossing trip another switch to raise the gate and stop the lights.

I'm totally stumped and would very much appreciate any help or advice you guys can give me on how to add in the extra switch and servos to my sketch/project.

Thanks for your time Guys  smiley


Code:
// set pin numbers:
int buttonPin = 2;     // the number of the pushbutton pin

// variables will change:
int buttonState = 0;         // variable for reading the pushbutton status

void setup() {
  // initialize the LED pin as an output:
  pinMode(12, OUTPUT);  // crossing inactive RED
  pinMode(11, OUTPUT);  // crossing active GREEN
  
  pinMode(10, OUTPUT);  // crossing lights RED
  pinMode(9, OUTPUT);   // crossing lights RED
  
  // initialize the pushbutton pin as an input:
  pinMode(buttonPin, INPUT);    
  }
  
  // the loop routine runs and stops after last command
void loop() {
  
  int buttonState = digitalRead(buttonPin);
  
    // the switch has been activated and the program can run
  if (buttonState == HIGH) {
     tone(8, 550, 750);      // crossing activated alarm
     digitalWrite(11, HIGH); // traffic stopped
     delay(1000);
     digitalWrite(11, LOW);  
     digitalWrite(10, LOW);  // crossing LEDs off
     digitalWrite(9, LOW);    
     delay(150);
     digitalWrite(9, HIGH);  // turn all crossing LEDs on for 2.5 seconds
     digitalWrite(10, HIGH);
     delay(2500);
     digitalWrite(9, HIGH);  // left flash
     digitalWrite(10, LOW);  // right off
     delay(500);
     digitalWrite(10, HIGH); // right flash
     digitalWrite(9, LOW);   // left off
     delay(500);
     digitalWrite(9, HIGH);  // crossing LEDs on
     digitalWrite(10, HIGH);
     delay(2500);
     digitalWrite(10, LOW);  // crossing LEDs off
     digitalWrite(9, LOW);  
     tone(8, 550, 750);      // crossing inactive alarm
     digitalWrite(12, HIGH); // crossing inactive
     delay(1500);
     digitalWrite(12, LOW);  // traffice can cross
  }

  
}
« Last Edit: February 23, 2013, 04:55:24 am by aussiefantom » Logged

Global Moderator
UK
Offline Offline
Brattain Member
*****
Karma: 310
Posts: 26637
I don't think you connected the grounds, Dave.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

What does your sketch do that it should not, and what does it not do that it should?
Logged

"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

Australia
Offline Offline
Newbie
*
Karma: 0
Posts: 26
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

At the moment the sketch I added to previous post works fine. When I push the test button a green led lights up and a piezo alarm sounds which tells me the program is active then the lights start flashing (I shortened the sketch cause there are so many delays) then they stop flashing and the piezo alarm sounds again and the red led lights up telling me the program has finished.

That part of the program I had no problem with as I modified the blinking LED sketch and added the "if" statement to allow the button to be read.

My problem is adding the second switch and the servo commands in the right places to make the whole thing fully functional.

I'm sorry if I seem hard to understand or aren't giving you enough info
Logged

Global Moderator
UK
Offline Offline
Brattain Member
*****
Karma: 310
Posts: 26637
I don't think you connected the grounds, Dave.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

The first thing is all those calls to "delay()" will have to go, or you're never going to detect the second switch in a timely manner.
Look at the blink without delay example to get a feel for the techniques you will need to do this.
Break down the light and servo sequence into a sequence of transitions and states.
Logged

"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

Australia
Offline Offline
Newbie
*
Karma: 0
Posts: 26
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Break down the light and servo sequence into a sequence of transitions and states.

Sorry if I sound dumb but what is meant by this? Am I to do the two separately then integrate them into the one?

I've been doing this for 2 weeks and I've learnt alot but there are some things I just can't get my head around.
Logged

Offline Offline
Faraday Member
**
Karma: 62
Posts: 3080
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

On the arduino,  your setup() function runs once and your loop() function runs continuously, for ever, until you turn of the power or upload a new sketch or reset the arduino.

Suppose you want your level crossing to close for four seconds.
You could close the gates,  ring the bell,  delay for four seconds,  and then open the gates.
Actually,  the above sentence is what YOU SHOULD NOT DO.

What you should do is this:

When the button or reed switch or whatever gets triggered,  you close the gate,  ring the bell,
and remember somehow what the time will be,  four seconds from now ( there are several ways
of doing this ).   Then your loop function runs,   every few milliseconds,   and one of the things
it does each cycle,  is check whether the four seconds is finished yet.   When the four seconds
is finished, it opens the gate and stops ringing the bell.   It can also check other things and do
other things while this is happening.

Look at the "blink without delay" example sketch for the recommended way of doing this,
there are other ways of doing this also.

Logged

UK
Offline Offline
Faraday Member
**
Karma: 100
Posts: 4153
Where is your SSCCE?!?!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

What michinyon is describing is called a Finite State Machine.

I wrote a tutorial a while back about them: http://hacking.majenko.co.uk/finite-state-machine
Logged

Get 10% off all 4D Systems TFT screens this month: use discount code MAJENKO10

Australia
Offline Offline
Newbie
*
Karma: 0
Posts: 26
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks for the tips guys.. I've nad a look at the link you posted majenko and it was very good.. I now have to work out how to integrate my coding with the one you created.

The more tips I get the better i'll become.
« Last Edit: February 23, 2013, 05:17:26 pm by aussiefantom » Logged

Australia
Offline Offline
Newbie
*
Karma: 0
Posts: 26
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I know I'm going to sound like a real dumba** but I don't understand how the blink without delay works. Can someone explain it to me in dumba** terms?

Sorry to be a pain
Logged

Croatia
Offline Offline
God Member
*****
Karma: 13
Posts: 524
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

You check the time and store it in a variable.
Later on you check time again and compare it with the time stored in the variable. If the predetermined period has not yet elapsed, you go about your business, do something else.
You then check again. If the predetermined period elapsed you do what you are waiting to do and store current time in the variable for later usage.
Logged

Australia
Offline Offline
Newbie
*
Karma: 0
Posts: 26
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Well its been almost 3 weeks since I started this little project and I have almost got it down pat but there is one part I need a little help with.

Code:
#include <Servo.h>

Servo myservo;
  
const int R1 = 9;  // 1st Red LED
const int R2 = 10;  // 2nd Red LED
const int G = 11;  // Green Active LED
const int R = 12;  // Red inactive LED
const int buttonPin = 2; // pushbutton pin


int buttonState = 0;     // variable for reading the pushbutton status
int running = 0;
int long interval = 500;
long previousMillis = 0;
int R1State = HIGH;
int pos = 0;

void setup() {
  pinMode(R1, OUTPUT);
  pinMode(R2, OUTPUT);
  pinMode(G, OUTPUT);
  pinMode(R, OUTPUT);
  pinMode(buttonPin, INPUT);    
  myservo.attach(7);
  digitalWrite(buttonPin, HIGH);

}
  
  // the loop routine runs and stops after last command
void loop() {
  
  int buttonState = digitalRead(buttonPin);
  
      
    // the switch has been activated and the program can run
  if (buttonState == HIGH && running == 0) {
    int running = 1;
     tone(8, 550, 750); // play SOUND
     digitalWrite(G, HIGH); // turn on GREEN LED
     myservo.write(45);
     delay(1500);
     digitalWrite(G, LOW); // turn off GREEN LED
     digitalWrite(R2, LOW); // turn the LED off
     digitalWrite(R1, LOW); // turn the LED off
     delay(250);
     digitalWrite(R1, HIGH); // turn the LED on
     digitalWrite(R2, HIGH); // turn the LED on
     delay(2500);
           buttonState = digitalRead(buttonPin);
        while(buttonState == LOW && running == 1)  {

// Timer used instead of delay to allow input to be read at the same time
          unsigned long currentMillis = millis();
          
          if(currentMillis - previousMillis > interval) {
            previousMillis = currentMillis;
            
            if (R1State == HIGH){ // Switches lights over
              digitalWrite(R1, LOW);
              digitalWrite(R2, HIGH);
              R1State = LOW;
            }
            else {
              digitalWrite(R1, HIGH); // Switches lights over
              digitalWrite(R2, LOW);
              R1State = HIGH;
            }
          }
          else {
 // Terminates program and switches off lights if the trigger input is detected
            buttonState = digitalRead(buttonPin);
            if (buttonState == HIGH){
              digitalWrite(10, LOW); // turn the LED off
              digitalWrite(9, LOW); // turn the LED off
              tone(8, 550, 1000); // play SOUND
              digitalWrite(12, HIGH); // turn on RED LED
              delay(1500);
              myservo.write(0);
              digitalWrite(12, LOW); // turn off RED LED
              int R1State = LOW;
              delay(5000);
              int running = 0;
              break;
            }
          }
        }
  }
}

My problem is that I have tried to incorporate servo code into the sketch to make the boom gates on the level crossing  lower and raise slowly as with real ones but I can only get them to go up to 45' and down to 0' in one hit instead of in increments.

I have tried to insert the servo code where I need it but it won't work how can I fix it?
« Last Edit: March 15, 2013, 05:33:36 am by aussiefantom » Logged

UK
Offline Offline
Faraday Member
**
Karma: 100
Posts: 4153
Where is your SSCCE?!?!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

You basically need to have a variable in which you store the current angle of the boom.  Then you slowly (by comparing another variable to millis()) increase / decrease that variable until you have the desired final angle.  Every time you increase / decrease the angle, you do the servo.write call.

A little function such as (untested):
Code:
void moveTo(unsigned char angle)
{
  static unsigned char currentAngle = 0;
  if (currentAngle < angle) {
    currentAngle++;
    myservo.write(currentAngle);
    return;
  }
  if (currentAngle > angle) {
    currentAngle--;
    myservo.write(currentAngle);
    return;
  }
}

will only move the boom by one degree per call, if it needs to move it at all.  In your main loop, you can do something like:
Code:
static unsigned long boomMoveTime = millis(); // These are either local static variables, or global non-static variables.
static unsigned char desiredBoomAngle = 0;
...
if (millis() - boomMoveTime > 10) {
  boomMoveTime = millis();
  moveTo(desiredBoomAngle);
}
...
if (whatever) {
  desiredBoomAngle = 45;
}

So, every 10 milliseconds you make a call to get the boom closer to its target angle, if it's not already there.  At any time in your main loop, you can then set the variable desiredBoomAngle, and it will instantly start to move the boom slowly up or down, to whatever the desiredBoomAngle variable is set to.
Logged

Get 10% off all 4D Systems TFT screens this month: use discount code MAJENKO10

Australia
Offline Offline
Newbie
*
Karma: 0
Posts: 26
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

will that work using a trigger to set then again to reset?
Logged

UK
Offline Offline
Faraday Member
**
Karma: 100
Posts: 4153
Where is your SSCCE?!?!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

will that work using a trigger to set then again to reset?
A trigger?  Not sure what you mean.

As long as the moveTo function is being called it will try to move the boom to a specific angle.  How you set what that angle should be (desiredBoomAngle) is entirely up to you.  Where you would normally do myservo.write(45), do desierdBoomAngle=45 instead.  The repeated, timed, call to moveTo() will do the actual moving, if moving is needed.
Logged

Get 10% off all 4D Systems TFT screens this month: use discount code MAJENKO10

Australia
Offline Offline
Newbie
*
Karma: 0
Posts: 26
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Sorry. By trigger I mean as the train passes over the switch ( miniature reed ) it starts the program running then when the train passes over the second switch it resets or terminates the program
Logged

Pages: [1] 2   Go Up
Jump to: