Australia
Offline
Newbie
Karma: 0
Posts: 18
|
 |
« on: February 23, 2013, 04:53:27 am » |
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  // 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
Brattain Member
Karma: 137
Posts: 19030
I don't think you connected the grounds, Dave.
|
 |
« Reply #1 on: February 23, 2013, 05:05:03 am » |
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.
|
|
|
|
Australia
Offline
Newbie
Karma: 0
Posts: 18
|
 |
« Reply #2 on: February 23, 2013, 05:49:13 am » |
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
Brattain Member
Karma: 137
Posts: 19030
I don't think you connected the grounds, Dave.
|
 |
« Reply #3 on: February 23, 2013, 06:29:23 am » |
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.
|
|
|
|
Australia
Offline
Newbie
Karma: 0
Posts: 18
|
 |
« Reply #4 on: February 23, 2013, 07:06:02 am » |
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
God Member
Karma: 9
Posts: 836
|
 |
« Reply #5 on: February 23, 2013, 07:12:42 am » |
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
Edison Member
Karma: 42
Posts: 2200
What a host of balls she had seen: gaity, the brass buttons...
|
 |
« Reply #6 on: February 23, 2013, 07:17:22 am » |
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
|
|
|
|
|
Australia
Offline
Newbie
Karma: 0
Posts: 18
|
 |
« Reply #7 on: February 23, 2013, 07:51:30 am » |
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
Newbie
Karma: 0
Posts: 18
|
 |
« Reply #8 on: February 24, 2013, 06:25:16 am » |
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
Full Member
Karma: 9
Posts: 243
|
 |
« Reply #9 on: February 24, 2013, 06:33:11 am » |
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
Newbie
Karma: 0
Posts: 18
|
 |
« Reply #10 on: March 15, 2013, 05:14:27 am » |
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. #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
Edison Member
Karma: 42
Posts: 2200
What a host of balls she had seen: gaity, the brass buttons...
|
 |
« Reply #11 on: March 15, 2013, 05:39:03 am » |
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): 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: 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
|
|
|
|
|
Australia
Offline
Newbie
Karma: 0
Posts: 18
|
 |
« Reply #12 on: March 15, 2013, 05:42:24 am » |
will that work using a trigger to set then again to reset?
|
|
|
|
|
Logged
|
|
|
|
|
UK
Offline
Edison Member
Karma: 42
Posts: 2200
What a host of balls she had seen: gaity, the brass buttons...
|
 |
« Reply #13 on: March 15, 2013, 05:44:10 am » |
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
|
|
|
|
|
Australia
Offline
Newbie
Karma: 0
Posts: 18
|
 |
« Reply #14 on: March 15, 2013, 05:48:06 am » |
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
|
|
|
|
|
|