About a year ago I started thinking about a way of automatising my model rollercoasters. After asking around I got to buying an Arduino.
Now 1 year later I have a result. Many setbacks and difficulties along the way though.
I'll let this video do the job for now.
Powered by an Arduino Mega. Motors are controlled using relays and transistors. Sensors are basic micro switches with an extra long handle.
Second I would like to thank Pieter Floris (www.floris.cc). I bought the Arduino through his webshop and he has been a great help finding solutions to problems. His customer service is superb and I would recommend anyone living in Holland or Belgium to check out his website and get involved in the magical world of the Arduino!
Note, comments are in Dutch, most of them are for debugging. The project is supposed to be versatile, so I'll leave them in so I can quickly find what everything does.
It's not entirely optimised and a few parts are left overs from debugging. However they do not affect the program itself.
#include <Servo.h>
//Servos
Servo gatesL;
Servo gatesR;
//Pins
const int modeSwitch = 22; // Sleutel schakelaar, kijkt in welke gebruiks modus de achtbaan moet werken.
const int gateSwitch = 26; // een draaischakelaar die de poortjes bedient.
const int dispatchButton = 28; // De knop die de trein laat vertrekken.
const int ledG = 34; // Dispatch knop lampje
const int ledR = 36; // Zolang de poortjes open zijn moet deze lamp branden
const int M12 = 42; // Motoren 1 en 2 (via relais) (lift+station)
const int M34 = 44; // Motoren 3 en 4 (via relais) (lift+station)
const int M56 = 46; // Motoren 5 en 6 (via relais) (remmen)
const int Sensor1 = 49; // Deze sensor zit bovenaan de lift
const int Sensor2 = 51; // Deze sensor zit op de remmen
const int Sensor3 = 53; // Deze sensor zit in het station
//Variables
int modeState;
int gateState;
int dispatchState;
int liftSensor;
int brakeSensor;
int stationSensor;
int ledGstate = LOW;
long previousMillis = 0;
long interval = 1000;
void setup() {
Serial.begin(9600);
//Input
pinMode(modeSwitch, INPUT);
pinMode(gateSwitch, INPUT);
pinMode(dispatchButton, INPUT);
pinMode(Sensor1, INPUT);
pinMode(Sensor2, INPUT);
pinMode(Sensor3, INPUT);
//Output
pinMode(ledG, OUTPUT);
pinMode(ledR, OUTPUT);
pinMode(M12, OUTPUT);
pinMode(M34, OUTPUT);
pinMode(M56, OUTPUT);
gatesR.attach(2);
gatesL.attach(3);
//Initialize
digitalWrite(ledG, LOW);
digitalWrite(ledR, LOW);
}
void loop() {
checkMode();
}
//Kijk of de schakelaar op Manual of Auto staat, ga aan de hand van de stand van deze knop door naar de betreffende modus.
void startupWait() {
delay(100);
checkMode();
}
void checkMode() {
delay(1000);
modeState = digitalRead(modeSwitch);
if (modeState == HIGH) {
Serial.println("MANUAL ----------------");
manualwaitMode();
}
else {
Serial.println("AUTO ++++++++++++++++++");
autowaitMode();
}
}
//Manual Mode
//Kijk of de poortjes open of dicht zijn, als de poortjes open zijn gaat het rode lampje branden en blijft de groene uit.
//Als de poortjes dicht zijn gaat hij door naar de volgende functie.
void manualwaitMode() {
delay(100);
manualMode();
}
void autowaitMode() {
delay(100);
autoMode();
}
void manualMode() {
gateState = digitalRead(gateSwitch);
delay(100);
//Poortjes open
if (gateState == LOW) {
gatesR.write(1);
gatesL.write(1);
digitalWrite(ledR, HIGH);
digitalWrite(ledG, LOW);
}
//Poortjes dicht
else {
gatesR.write(90);
gatesL.write(90);
digitalWrite(ledR, LOW);
digitalWrite(ledG, LOW);
dispatchMode();
}
}
// Wanneer de knop ingedrukt is vertrekt de trein, de groene lamp gaat aan en blijft aan. Ook moet hij de sensor op de lift gaan checken.
//Indien de knop niet ingedrukt is en de poortjes dicht zijn moet de groene lamp knipperen.
void dispatchMode() {
dispatchState = digitalRead(dispatchButton);
//Knop ingedrukt
if (dispatchState == LOW) {
Serial.println("Dispatch knop is een keer ingedrukt.");
digitalWrite(ledG, HIGH);
digitalWrite(M12, HIGH);
digitalWrite(M34, HIGH);
checkLift();
}
//Knop niet ingedrukt
else {
blinkG();
}
}
//Als de poortjes dicht zijn en de knop niet ingedrukt is blijft het lampje knipperen.
void blinkG() {
if (millis() - previousMillis > interval) {
// save the last time you blinked the LED
previousMillis = millis();
// if the LED is off turn it on and vice-versa:
if (ledGstate == LOW)
ledGstate = HIGH;
else
ledGstate = LOW;
// set the LED with the ledState of the variable:
digitalWrite(ledG, ledGstate);
}
}
//Waneer deze functie bereikt word moet hij de sensor blijven lezen todat hij aangeraakt is door de trein, pas dan mag het programma verder naar de volgende stap.
//Zoland de sensor niet aangeraakt is blijft hij deze stap herhalen.
//Wanneer de sensor aangeraakt is blijven de motoren nog eventjes door draaien en gaat daarna ook de groene lamp uit.Hierna moet hij door naar de volgende functie.
// N.B. De volgende functies (checkSensor) worden zowel door Manual als Auto gebruikt.
void checkLift() {
liftSensor = digitalRead(Sensor1);
//De trein is de sensor nog niet gepaseerd.
while(liftSensor == HIGH) {
Serial.println("Trein beklimt de lift.");
delay(100);
checkLift();
}
//De trein paseert de sensor
if(liftSensor == LOW) {
Serial.println("Trein passeert de top van de lift.");
delay(5000);
digitalWrite(ledG, LOW);
digitalWrite(M12, LOW);
digitalWrite(M34, LOW);
checkBrake();
}
}
//Zodra bij deze functie komt moet hij deze blijven herhalen todat de trein de sensor is gepaseerd. Pas dan mag hij door naar de volgende stap.
//Als de sensor is aangeraakt moeten er motoren gaan draaien en blijven draaien tot hij bij de volgende functie is.
void checkBrake() {
brakeSensor = digitalRead(Sensor2);
//Sensor nog niet aangeraakt
while(brakeSensor == HIGH) {
Serial.println("Trein volgt de rest van de baan.");
delay(100);
checkBrake();
}
//Trein passeert de sensor
if(brakeSensor == LOW) {
Serial.println("Trein rijdt de remmen in.");
digitalWrite(M56, HIGH);
checkStation();
}
}
//Deze functie moet zich blijven herhalen todat de trein de sensor is gepaseerd. Pas dan mag het programma opnieuw beginnen en kijken in welke gebruiks modus hij staat.
//Als de sensor is aangeraakt moeten de motoren stoppen met draaien en gaat hij terug naar de eerste functie.
void checkStation() {
stationSensor = digitalRead(Sensor3);
//Sensor is nog niet aangeraakt
while(stationSensor == HIGH) {
Serial.println("Trein is nog niet in het station.");
delay(1000);
checkStation();
}
//Sensor is aangeraakt
if(stationSensor == LOW) {
Serial.println("Trein is wel in het station.");
digitalWrite(M56, LOW);
delay(100);
/* restart program */
restartP();
}
}
//Auto
//De volgorde waarin de achtbaan dingen moet doen staat hierin gedefinieerd. Poortjes open, poortjes dicht, vertrekken. Zodra deze functie afgelopen is moet hij kijken of de trein al bovenaan de lift is.
void autoMode() {
delay(1000);
digitalWrite(ledG, HIGH);
delay(1000);
digitalWrite(ledG, LOW);
delay(1000);
digitalWrite(ledG, HIGH);
delay(1000);
digitalWrite(ledG, LOW);
delay(1000);
gatesR.write(1);
gatesL.write(1);
digitalWrite(ledR, HIGH);
delay(10000);
gatesR.write(90);
gatesL.write(90);
digitalWrite(ledR, LOW);
delay(1000);
digitalWrite(ledG, HIGH);
delay(1000);
digitalWrite(ledG, LOW);
delay(1000);
digitalWrite(ledG, HIGH);
delay(1000);
digitalWrite(ledG, LOW);
delay(1000);
digitalWrite(ledG, HIGH);
digitalWrite(M12, HIGH);
digitalWrite(M34, HIGH);
checkLift();
}
void restartP() // Restarts program from beginning but does not reset the peripherals and registers
{
asm volatile (" jmp 0");
}