Project Phase: Arduino powered model roller coaster

Old thread here(videos of V1.1 on page 2):
http://arduino.cc/forum/index.php/topic,8491.0.html

The current version of this project is V1.2 which is a revamped cleaner code of V1.1. Both versions only allow for 1 train to go around the track in either manual or automatic mode.
Recently I decided to start coding a new version which allows for multiple train on the track. 2 Would be enough but the way I want to code is so it doesn’t matter how many trains are on the track as long as there are enough block sections to accommodate for the trains.

The way I want to set up this whole project is to make each section (block) work standalone. The old version used a pre-programmed ride cycle that would just start reading the next sensor when the previous one was touched. Very basic. The new version cycles through the block sections and checks to see if it meets the 2 or 3 requirements for it to let the train through. If it does the train will head for the next section. Otherwise it will be stopped dead in it’s tracks (lol pun) to prevent collisions.

Here is the code up until now which is far from finished and close to working at all:

#include <Servo.h>

// Servo Motors
Servo gatesServo1;
Servo gatesServo2;

//Pins
const int modeSwitch      = 22;    //Switch to select Auto/Manual mode
const int gateSwitch      = 26;    //Switch to open/close the station gates.
const int dispatchButton  = 28;    //Button to dispatch the train
const int trainSwitch     = 30;    //Amount of trains
const int ledG            = 34;    //Green LED, blink = ready to dispatch
const int ledR            = 36;    //Indicates the status from the station gates (Open/Closed)
const int motorSet1       = 42;    //Motors 1 and 2
const int motorSet2       = 44;    //Motors 3 and 4
const int motorSet3       = 46;    //Motors 5 and 6
const int sensorLift      = 49;    //Sensor on the lift
const int sensorBrakes    = 51;    //Sensor on the brakes
const int sensorStation   = 53;    //Sensor in the station

// Booleans
stationState = true;
brakeState = false;
liftState = false;

//Variables

//Others

void setup() {
  Serial.begin(9600);
  
  //Inputs
  pinMode(modeSwitch, INPUT);
  pinMode(gateSwitch, INPUT);
  pinMode(dispatchButton, INPUT);
  pinMode(sensorLift, INPUT);
  pinMode(sensorBrakes, INPUT);
  pinMode(sensorStation, INPUT);

  //Outputs
  pinMode(ledG, OUTPUT);
  pinMode(ledR, OUTPUT);
  pinMode(motorSet1, OUTPUT);
  pinMode(motorSet2, OUTPUT);
  pinMode(motorSet3, OUTPUT);
  gatesServo1.attach(2);
  gatesServo2.attach(3);
  
  //Initialize
  
}
 
 
void loop() {
  
  //Manual 1 train
  if(modeSwitch == HIGH && trainSwitch == HIGH) {
    
    //Gates
    if(gateSwitch == LOW && stationState == true) {
      gateServo1.write(1);
      gateServo2.write(1);
    }
    else {
      gateServo1.write(90);
      gateServo2.write(90);
    }
    
    if(gateSwitch == HIGH && stationState == true && dispatchButton == LOW) {
      Serial.println("DISPATCHED");
      //Motors Station On
      liftState = HIGH;
    }
    
    //The Lift
    if(liftState == true && brakeState == false){
      if(sensorLift == HIGH){
        digitalWrite(motorSet2, HIGH);
      }
      else {
        //wacht tot top gepasseerd (delay vervanger!!)
        digitalWrite(motorSet2, LOW);
        liftState = false;
      }
    }
    else { 
      digitalWrite(motorSet2, LOW);
    }
    
    //The Brakes
    if(brakeState == true && stationState && false){
      
    
  }
  
  //Manual 2 trains
  if(modeSwitch == HIGH && trainSwitch == LOW)  {
    
    
  }
  
  //Automatic 1 train
  if(modeSwitch == LOW && trainSwitch == HIGH)  {
    
    
  }
  
  //Automatic 2 trains
  if(modeSwitch == LOW && trainSwitch == LOW)  {
    
    
  }
}

THIS CODE IS FAR FROM FINISHED ADN HAS A LOT OF BUGS AND MESS-UPS. (Ugh, I haven’t coded in a while, takes some time to get back into it.)
The only thing that bugs me right now is that I don’t know how to initialize the coaster when it first boots up. I’m thinking about adding more sensors but that will be very expensive. When the coaster boots up there will be a train in the station and maybe (depending on the amount of trains which is interchangeable) on the brake section. I need it to somehow read the brake section on the first boot to determine the amount of trains on the track. Any help on how to do this is appreciated :slight_smile:

The current block sections are: Station, Lift, Brakes. Currently I have 3 sensors but I have a spare 4th laying around which can be added if necessary.

Double post, sorry for that:
I made some good progress on the code, it’s now able to handle 2 trains or a single train. You can see the 2 trains in the video here:

I can turn a switch to select single train mode or multiple train mode. It uses a realistic block section system that check if the train is allowed to advance to the next section.
Right now I’m using delays to help with some timing issues. But I want to get rid of those and find an alternative. I just can’t find out how to do this. I’ve looked around and it keeps redirecting me to the Blink Without delay example. I don’t really know how to modify this to a delay-like function. Anyone?? :smiley:

#include <Servo.h>

// Servo Motors
Servo gatesServo1;
Servo gatesServo2;

//Pins
const int modeSwitch      = 22;    //Switch to select Auto/Manual mode
const int trainSwitch     = 24;    //Amount of trains
const int gateSwitch      = 26;    //Switch to open/close the station gates.
const int dispatchButton  = 28;    //Button to dispatch the train
const int ledG            = 34;    //Green LED, blink = ready to dispatch
const int ledR            = 36;    //Indicates the status from the station gates (Open/Closed)
const int motorSet1       = 42;    //Motors 1 and 2
const int motorSet2       = 44;    //Motors 3 and 4
const int motorSet3       = 46;    //Motors 5 and 6
const int sensorLift      = 49;    //Sensor on the lift
const int sensorBrakes    = 51;    //Sensor on the brakes
const int sensorStation   = 53;    //Sensor in the station

//Integers
int gateState;
int dispatchState;
int trainState;
int modeState;
int liftSensor;
int stationSensor;
int brakesSensor;
int Aftel;

// Booleans
boolean stationState = true;
boolean brakesState = true;
boolean liftState = false;
boolean trackState = false;

//Variables
long previousMillis = 0;

//Intervals

//Others

void setup() {
  Serial.begin(9600);
  
  //Inputs
  pinMode(modeSwitch, INPUT);
  pinMode(trainSwitch, INPUT);
  pinMode(gateSwitch, INPUT);
  pinMode(dispatchButton, INPUT);
  pinMode(sensorLift, INPUT);
  pinMode(sensorBrakes, INPUT);
  pinMode(sensorStation, INPUT);

  //Outputs
  pinMode(ledG, OUTPUT);
  pinMode(ledR, OUTPUT);
  pinMode(motorSet1, OUTPUT);
  pinMode(motorSet2, OUTPUT);
  pinMode(motorSet3, OUTPUT);
  gatesServo1.attach(2);
  gatesServo2.attach(3);
  
  //Initialize
  
}
 
 
void loop() {
    
  //Handmatig 1 trein
  modeState = digitalRead(modeSwitch);
  trainState = digitalRead(trainSwitch);
  if(modeState == HIGH && trainState == HIGH) {
    manOne();
  }
  if(modeState == HIGH && trainState == LOW) {
    manTwo();
  }
  
  if(trainState == HIGH){
    Serial.println("EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE");
  }
  
}

  
void manOne(){
    //Poortjes
    gateState = digitalRead(gateSwitch);
    if(gateState == HIGH && stationState == true) {
      gatesServo1.write(1);
      gatesServo2.write(1);
      digitalWrite(ledR, LOW);
      Serial.println("GESLOTEN");
    }
    else {
      gatesServo1.write(90);
      gatesServo2.write(90);
      digitalWrite(ledR, HIGH);
      Serial.println("OPEN");
    }
    
    //Het Station
    dispatchState = digitalRead(dispatchButton);
    if(gateState == HIGH && stationState == true && dispatchState == LOW && liftState == false) {
      Serial.println("DISPATCHED");
      digitalWrite(motorSet3, HIGH);
      delay(2000); //TIJDELIJK OM TE TESTEN
      digitalWrite(motorSet1, HIGH);
      delay(500);
      digitalWrite(motorSet3, LOW);
      liftState = true;
      stationState = false;
      brakesState = false;
      delay(1800);
      digitalWrite(motorSet1, LOW);
      }
      
      else{
      digitalWrite(motorSet3, LOW);
    }
    
    //De Lift
    if(liftState == true && brakesState == false){
      
      liftSensor = digitalRead(sensorLift);
      if(liftSensor == HIGH){
        digitalWrite(motorSet1, HIGH);
      }
      else {
        delay(1000); //TIJDELIJK OM TE TESTEN!
        digitalWrite(motorSet1, LOW);
        liftState = false;
      }
    }
    else { 
      digitalWrite(motorSet2, LOW);
    }

   brakesSensor = digitalRead(sensorBrakes);
   if(brakesSensor == LOW){
     brakesState = true;
   }
  
    //De Remmen
    if(brakesState == true && stationState == false){    
      digitalWrite(motorSet2, HIGH);
    }
    else {
      digitalWrite(motorSet2, LOW);
    }
    
    //Binnekomen Station
    stationSensor = digitalRead(sensorStation);
    if(brakesState == true && stationState == false && stationSensor == LOW){
      digitalWrite(motorSet3, HIGH);
      delay(2800);
      brakesState = false;
      stationState = true;
    }

//Debuggen
if(brakesState == false){
  Serial.println("FALSE");
}

else{
  Serial.println("TRUE");
}
  }

  
void manTwo() {   
   Serial.println("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); 
    //Poortjes
    gateState = digitalRead(gateSwitch);
    if(gateState == HIGH && stationState == true) {
      gatesServo1.write(1);
      gatesServo2.write(1);
      digitalWrite(ledR, LOW);
      Serial.println("GESLOTEN");
    }
    else {
      gatesServo1.write(90);
      gatesServo2.write(90);
      digitalWrite(ledR, HIGH);
      Serial.println("OPEN");
    }
    
    //Het Station
    dispatchState = digitalRead(dispatchButton);
    if(gateState == HIGH && stationState == true && dispatchState == LOW && liftState == false /*&& brakesState == true*/) {
      Serial.println("DISPATCHED");
      digitalWrite(motorSet3, HIGH);
      delay(2000); //TIJDELIJK OM TE TESTEN
      digitalWrite(motorSet1, HIGH);
      delay(500);
      digitalWrite(motorSet3, LOW);
      liftState = true;
      stationState = false;
      delay(1800);
      digitalWrite(motorSet1, LOW);
      }
      
      else{
      digitalWrite(motorSet3, LOW);
    }
    
    //De Lift
    if(liftState == true && brakesState == false){
      
      liftSensor = digitalRead(sensorLift);
      if(liftSensor == HIGH && brakesState == false){
        digitalWrite(motorSet1, HIGH);
      }
      else {
        delay(1000); //TIJDELIJK OM TE TESTEN!
        digitalWrite(motorSet1, LOW);
        liftState = false;
        trackState = true;
      }
    }
    else { 
      digitalWrite(motorSet2, LOW);
    }

   //Lift Beveiliging
   trainState = digitalRead(trainSwitch);
   if(brakesState == true || trackState == true){
     digitalWrite(motorSet1, LOW);
     }

   brakesSensor = digitalRead(sensorBrakes);
   if(brakesSensor == LOW){
     brakesState = true;
     trackState = false;
   }
  
    //De Remmen
    if(brakesState == true && stationState == false){    
      digitalWrite(motorSet2, HIGH);
    }
    else {
      digitalWrite(motorSet2, LOW);
    }
    
    //Binnekomen Station
    stationSensor = digitalRead(sensorStation);
    if(brakesState == true && stationState == false && stationSensor == LOW){
      digitalWrite(motorSet3, HIGH);
      delay(2800);
      brakesState = false;
      stationState = true;
    }

//Debuggen
if(brakesState == false){
  Serial.println("FALSE");
}

else{
  Serial.println("TRUE");
}
}

pretty neat. what is the track system used?

Sweet! I don't suppose you'd happen to have a small camera to film the ride? hopeful

CrossRoads: pretty neat. what is the track system used?

It's called K'nex, sadly this track type is not sold anymore, they moved on to prefabricated sections which can bend.

karlboll: Sweet! I don't suppose you'd happen to have a small camera to film the ride? hopeful

Actually, I do!

Actually, I do!

Then .. could I please have a video of that so I can stick my face really close to the screen and pretend I'm riding a giant k'nex rollercoaster. :D

karlboll:

Actually, I do!

Then … could I please have a video of that so I can stick my face really close to the screen and pretend I’m riding a giant k’nex rollercoaster. :smiley:

Currently waiting for the HD version of that camera, I ordered it 2 weeks ago… Just be patient :slight_smile:
The train with the camera mounted on it will be pushed by hand around the track. If I would just let it do it’s lap it will be so fast you won’t see a thing.

I’ll make a video once the program is done.

I had a K'Nex coaster, it was made of regular K'Nex I think

I still don't know how to replace the delays in the code with an alternative so any help is still appreciated. I'm considering reading the sensors using the Attach Interrupt pins on the Arduino Mega board so it reads the sensors anyway, but still It's not going to make it look any more pretty!

Here is the onride video shot with my 808 Car Keychain #11 Mini Spy-cam (look it up on google or e-bay, they come for about 30 dollars(the HD version that is))

http://www.youtube.com/watch?v=Er_JIcsVbAI

I could suggest replace the delay with reading millis() at start of what is now your delay, and then re-reading on the next pass thru loop, and so on until the time has elapsed, then clearing the time count and proceeding once it has elapsed. Do you really need other stuff to be going on during what is now your delay time?

YES! Weeeeeeeehhh!!! Oh, thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you!

CrossRoads: I could suggest replace the delay with reading millis() at start of what is now your delay, and then re-reading on the next pass thru loop, and so on until the time has elapsed, then clearing the time count and proceeding once it has elapsed. Do you really need other stuff to be going on during what is now your delay time?

I'm a though learner when it comes to coding, can you post a quick example?

The stuff really needs to be going during the delays as I don't have enough sensors. The delays now allow the train to catch the chain on the lift and help with positioning the train in the station.

Right from the start let me tell you this probably isn’t correct, but I believe it’s close. If someone could look it over and correct anything that’s needed it would be appreciated.

I marked my comments with my user name, biocow, so you can search for what I did. You had a 28 second delay near the end and I altered it a bit. I also added a few variables in the setup.

so what this will do is while your if statement is true:

if(brakesState == true && stationState == false && stationSensor == LOW){

The code will go into the next if and do nothing and just pass right through for the first 27 seconds. When 28 seconds have passed then it will execute changing the break and station vars.

If anything is wrong here then it’s this line:

previousBinnekomenMillis = currentBinnekomenMillis;

I think I have that in the wrong place or am handling it wrong.

Good luck.

[[EDIT]]

Sorry, changed the code. I think it might be right now.

#include <Servo.h>

// Servo Motors
Servo gatesServo1;
Servo gatesServo2;

//Pins
const int modeSwitch      = 22;    //Switch to select Auto/Manual mode
const int trainSwitch     = 24;    //Amount of trains
const int gateSwitch      = 26;    //Switch to open/close the station gates.
const int dispatchButton  = 28;    //Button to dispatch the train
const int ledG            = 34;    //Green LED, blink = ready to dispatch
const int ledR            = 36;    //Indicates the status from the station gates (Open/Closed)
const int motorSet1       = 42;    //Motors 1 and 2
const int motorSet2       = 44;    //Motors 3 and 4
const int motorSet3       = 46;    //Motors 5 and 6
const int sensorLift      = 49;    //Sensor on the lift
const int sensorBrakes    = 51;    //Sensor on the brakes
const int sensorStation   = 53;    //Sensor in the station

// Used for delay - biocow
long previousBinnekomenMillis = 0;        // will store last time LED was updated
long binnekomenDelayTime = 2800;


//Integers
int gateState;
int dispatchState;
int trainState;
int modeState;
int liftSensor;
int stationSensor;
int brakesSensor;
int Aftel;

// Booleans
boolean stationState = true;
boolean brakesState = true;
boolean liftState = false;
boolean trackState = false;

// Binnekomen time on or off - biocow
boolean binnekomenTimerOn = false;


//Variables
long previousMillis = 0;

//Intervals

//Others

void setup() {
  Serial.begin(9600);
  
  //Inputs
  pinMode(modeSwitch, INPUT);
  pinMode(trainSwitch, INPUT);
  pinMode(gateSwitch, INPUT);
  pinMode(dispatchButton, INPUT);
  pinMode(sensorLift, INPUT);
  pinMode(sensorBrakes, INPUT);
  pinMode(sensorStation, INPUT);

  //Outputs
  pinMode(ledG, OUTPUT);
  pinMode(ledR, OUTPUT);
  pinMode(motorSet1, OUTPUT);
  pinMode(motorSet2, OUTPUT);
  pinMode(motorSet3, OUTPUT);
  gatesServo1.attach(2);
  gatesServo2.attach(3);
  
  //Initialize
  
}
 
 
void loop() {
    
  //Handmatig 1 trein
  modeState = digitalRead(modeSwitch);
  trainState = digitalRead(trainSwitch);
  if(modeState == HIGH && trainState == HIGH) {
    manOne();
  }
  if(modeState == HIGH && trainState == LOW) {
    manTwo();
  }
  
  if(trainState == HIGH){
    Serial.println("EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE");
  }
  
}

  
void manOne(){
    //Poortjes
    gateState = digitalRead(gateSwitch);
    if(gateState == HIGH && stationState == true) {
      gatesServo1.write(1);
      gatesServo2.write(1);
      digitalWrite(ledR, LOW);
      Serial.println("GESLOTEN");
    }
    else {
      gatesServo1.write(90);
      gatesServo2.write(90);
      digitalWrite(ledR, HIGH);
      Serial.println("OPEN");
    }
    
    //Het Station
    dispatchState = digitalRead(dispatchButton);
    if(gateState == HIGH && stationState == true && dispatchState == LOW && liftState == false) {
      Serial.println("DISPATCHED");
      digitalWrite(motorSet3, HIGH);
      delay(2000); //TIJDELIJK OM TE TESTEN
      digitalWrite(motorSet1, HIGH);
      delay(500);
      digitalWrite(motorSet3, LOW);
      liftState = true;
      stationState = false;
      brakesState = false;
      delay(1800);
      digitalWrite(motorSet1, LOW);
      }
      
      else{
      digitalWrite(motorSet3, LOW);
    }
    
    //De Lift
    if(liftState == true && brakesState == false){
      
      liftSensor = digitalRead(sensorLift);
      if(liftSensor == HIGH){
        digitalWrite(motorSet1, HIGH);
      }
      else {
        delay(1000); //TIJDELIJK OM TE TESTEN!
        digitalWrite(motorSet1, LOW);
        liftState = false;
      }
    }
    else { 
      digitalWrite(motorSet2, LOW);
    }

   brakesSensor = digitalRead(sensorBrakes);
   if(brakesSensor == LOW){
     brakesState = true;
   }
  
    //De Remmen
    if(brakesState == true && stationState == false){    
      digitalWrite(motorSet2, HIGH);
    }
    else {
      digitalWrite(motorSet2, LOW);
    }
    
    //Binnekomen Station
    stationSensor = digitalRead(sensorStation);
    if(brakesState == true && stationState == false && stationSensor == LOW){
      digitalWrite(motorSet3, HIGH);
      delay(2800);
      brakesState = false;
      stationState = true;
    }

//Debuggen
if(brakesState == false){
  Serial.println("FALSE");
}

else{
  Serial.println("TRUE");
}
  }

  
void manTwo() {   
   Serial.println("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); 
    //Poortjes
    gateState = digitalRead(gateSwitch);
    if(gateState == HIGH && stationState == true) {
      gatesServo1.write(1);
      gatesServo2.write(1);
      digitalWrite(ledR, LOW);
      Serial.println("GESLOTEN");
    }
    else {
      gatesServo1.write(90);
      gatesServo2.write(90);
      digitalWrite(ledR, HIGH);
      Serial.println("OPEN");
    }
    
    //Het Station
    dispatchState = digitalRead(dispatchButton);
    if(gateState == HIGH && stationState == true && dispatchState == LOW && liftState == false /*&& brakesState == true*/) {
      Serial.println("DISPATCHED");
      digitalWrite(motorSet3, HIGH);
      delay(2000); //TIJDELIJK OM TE TESTEN
      digitalWrite(motorSet1, HIGH);
      delay(500);
      digitalWrite(motorSet3, LOW);
      liftState = true;
      stationState = false;
      delay(1800);
      digitalWrite(motorSet1, LOW);
      }
      
      else{
      digitalWrite(motorSet3, LOW);
    }
    
    //De Lift
    if(liftState == true && brakesState == false){
      
      liftSensor = digitalRead(sensorLift);
      if(liftSensor == HIGH && brakesState == false){
        digitalWrite(motorSet1, HIGH);
      }
      else {
        delay(1000); //TIJDELIJK OM TE TESTEN!
        digitalWrite(motorSet1, LOW);
        liftState = false;
        trackState = true;
      }
    }
    else { 
      digitalWrite(motorSet2, LOW);
    }

   //Lift Beveiliging
   trainState = digitalRead(trainSwitch);
   if(brakesState == true || trackState == true){
     digitalWrite(motorSet1, LOW);
     }

   brakesSensor = digitalRead(sensorBrakes);
   if(brakesSensor == LOW){
     brakesState = true;
     trackState = false;
   }
  
    //De Remmen
    if(brakesState == true && stationState == false){    
      digitalWrite(motorSet2, HIGH);
    }
    else {
      digitalWrite(motorSet2, LOW);
    }
    
    //Binnekomen Station
    stationSensor = digitalRead(sensorStation);
    if(brakesState == true && stationState == false && stationSensor == LOW){ 
	  // Binnekomen Station Delay
	  if(binnekomenDelayOn == false) {
	  	binnekomenDelayOn == true; // turn the timer on
		previousBinnekomenMillis = millis(); // get the start time
	  } else {
	    // if the timer is on check how much time has gone by
	    unsigned long currentBinnekomenMillis = millis(); // get the current time
	    if(currentBinnekomenMillis - previousBinnekomenMillis > binnekomenDelayTime) {
	    	// 28 seconds has gone by. Change vars 
		  digitalWrite(motorSet3, HIGH);
    	  brakesState = false;
      	  stationState = true;
		  binnekomenDelayOn = false; // turn the timer off
        }
	  }
	}

//Debuggen
if(brakesState == false){
  Serial.println("FALSE");
}

else{
  Serial.println("TRUE");
}
}

rides by in the rollercoaster -Wheeeeee!

Thanks Biocow! I will test it out later this week as I am in the middle of my test week at school. I will let you know if it works!

rides by in the rollercoaster with all his friends -Wheeeeee! -I'm gonna be sick!

Sorry Biocow but it didn't work. I think you have gotten it wrong:

if(brakesState == true && stationState == false && stationSensor == LOW){

The code will go into the next if and do nothing and just pass right through for the first 27 seconds. When 28 seconds have passed then it will execute changing the break and station vars.

It's supposed to leave the motors on for 2,8 seconds and then turn them off but still read the sensor while doing it. I was thinking about attach interrupts, but I want to be able to the project with more sensors, and the mega doesn't have an infinite amount of pins that are capable of that.