Railuino train going back and forth

hi

thanks for reading my post!

I am wanting to control a Märklin model train using Railuino / Candiy Bus shield / Arduino Mega

the concept:

a museum visitor pushes a button
the sound of a train can be heard starting
the train goes forward ( the track is straight, with end stops, 6 metres long)
when is approaches the end of the track a sensor detects the train and stops it.
shortly thereafter the trains goes in the opposite direction
until it reaches the other end of the track, is detected by a second sensor and is stopped.

end of the loop

until the next visitor comes in

an emergency loop, activated by a button, needs to be built in case the train is somehow stuck in the middle and the whole thing can start from the beginning.

I am having a hard time with the sensors at the end stopping the movement of the train.
in the latest edition of the code I do not even get the train going forward. I tried if / else, while, switch...so far no go

I am not the complete newbie, but I am no pro either...I have to do this kind of stuff once in a while and seem to have to learn all over again.

any help would be super appreciated.
My code is attached

i

train_back_and_forth.ino (3.27 KB)

#include <Railuino.h>


const word    LOCO  = ADDR_MM2 + 78;      //motorola MM2 address
const word    TIME  = 2000;
const boolean DEBUG = true;

// Créer un contrôleur Railuino
TrackController ctrl(0xdf24, DEBUG);

const int buttonPin1 = 12;      // main switch
const int buttonPin2 = 3;      // switch at end of the forward movement
const int buttonPin3 = 4;      // switch at end of the backward movement
int ledPin = 9;            //LED
int calibrationTime = 5;
int buttonState1 = LOW;
int buttonState2 = LOW;
int buttonState3 = LOW;




void setup() {
  Serial.begin(9600);
  // Attendre l'établissement de la connexion
  while (!Serial);
  // Démarrer le contrôleur
  ctrl.begin();

  Serial.println("Mise sous tension - Power on");
  ctrl.setPower(true);
  digitalWrite(12, LOW);        // these three lines look to me redundant but when I remove them programm is buggy
  digitalWrite(3, LOW);
  digitalWrite(4, LOW);
  pinMode(10, OUTPUT);
  pinMode(ledPin, OUTPUT);
  pinMode(buttonPin1, INPUT);
  pinMode(buttonPin2, INPUT);
  pinMode(buttonPin3, INPUT);
}







void loop() {

  buttonState1 = digitalRead(buttonPin1); //main switches turned on

  switch (buttonState1) {

    case 'HIGH':
      delay(1000);
      digitalWrite(10, HIGH);   // turn the Sound on
      delay(1000);
      digitalWrite(10, LOW); // deactivate sound
      delay(5000);
      delay(50);
      break;

    case 'LOW':
      digitalWrite(ledPin, HIGH);
      delay(500);
      digitalWrite(ledPin, LOW);
      delay(500);
  }
}


void forward() {              //loop for train going forward

  buttonState2 = digitalRead(buttonPin2);      // switch to detect end of the track going forward

  switch (buttonState2) {

    case 'HIGH':                              //train met the switch
      digitalWrite(ledPin, LOW);                //train should stop but does not
      ctrl.setLocoSpeed(LOCO, 0);
      Serial.println("stop 1");
      delay(50);
      pause();                        // go to pause()
      delay(50);
      break;                          //exit the loop ?

    case 'LOW':                  // if train has not met the switch it goes forward
      Serial.println("Marche avant - Direction forward");
      digitalWrite(ledPin, HIGH);
      ctrl.setLocoDirection(LOCO, DIR_FORWARD);
      ctrl.setLocoSpeed(LOCO, 1000);      //max speed
      delay(1000);              // no break to stay in the loop
  }
}

void pause() {            // short pause

  ctrl.setLocoSpeed(LOCO, 0);
  delay(500);
  backward();
  delay(50)

}

void backward() {                // loop for train going backward

  buttonState3 = digitalRead(buttonPin3);          // switch to detect end of the track going backward

  switch (buttonState3) {

    case 'HIGH':
      Serial.println("stop 2");          // if train reaches the end of the track going backward
      digitalWrite(ledPin, LOW);
      ctrl.setLocoSpeed(LOCO, 0);            // train stops
      delay(500);
      break;

    case 'LOW':                                          // train has not met the switch and goes backward
      Serial.println("Marche arriere - Direction reverse");
      digitalWrite(ledPin, HIGH);
      ctrl.setLocoDirection(LOCO, DIR_REVERSE);
      ctrl.setLocoSpeed(LOCO, 1000);      //max speed
      delay(1000);              // no break to stay in the loop

  }

}

Specifically

    case 'LOW':

Well, there's nothing syntactically wrong with 'LOW' and 'HIGH' but they're never going to be the same as 0 or 1, so those comparisons will always fail.
Use LOW and HIGH instead.
Also, using switch/case for a binary comparison is overkill - use if/else instead.

You never call any of the function forward().

And this comment does not make sense

void backward() {                // loop for train going backward

  buttonState3 = digitalRead(buttonPin3);          // switch to detect end of the track going backward

  switch (buttonState3) {

    case 'HIGH':
      ...
      ...
      break;

    case 'LOW':                                          // train has not met the switch and goes backward
      ...
      ...
      delay(1000);              // no break to stay in the loop

  }
}

The break terminates the case, not the loop.

Thanks for the fast comments so far.

I did have a version with if / else

But I could not break out of the forward movement.
My sensor did not terminate the movement.

Tried both
If (LOW){
Pause();
Delay();

}
else {
//Train goes forward

Here tried both with short delay, thinking that it would loop, hence keep going, or 33s long, the time it takes to reach the end
}

if (LOW) is never going to be true either.

if (buttonState1 == LOW) at least has a chance of doing what you want.

If you want responsiveness, I suggest you get rid of the delay()s

Hi Awol
Yes you are right
It is also what I meant.
But in my case somehow did not do what it should. In this case go forward until the sensor / switch stops it and the train goes forward.

Well, there's the problem that you don't call forward()

case 'LOW':

I believe LOW evaluates to 0 and 'LOW' evaluates to 48 (ascii "0") which is not 0 so would evaluate to true (1 or HIGH).

edgemoron:

case 'LOW':

I believe LOW evaluates to 0 and 'LOW' evaluates to 48 (ascii "0")

People believe the strangest things, don't they?

You can print the value of 'LOW', you know.

Would 'LOW' match 0 or false in a case statement?

edgemoron:
Would 'LOW' match 0 or false in a case statement?

Neither.

Just as I thought... :confused:

And, both 'LOW' and 'HIGH' are true, though neither is == true. :slight_smile:

I knew it! :slight_smile:

Apparently, multi-character constants evaluate to only the lower 16 bits, even when I assign or cast it to a uint32_t.

'LOW' == 'OW' == 0x4F57 == 20311
'HIGH' == 'GH' == 0x4748 == 18248

I expected 'HIGH' to be 0x48494748

I expected 'HIGH' to be 0x48494748

And such it is on a platform with a 32 bit int.

a museum visitor pushes a button
the sound of a train can be heard starting
the train goes forward ( the track is straight, with end stops, 6 metres long)
when is approaches the end of the track a sensor detects the train and stops it.
shortly thereafter the trains goes in the opposite direction
until it reaches the other end of the track, is detected by a second sensor and is stopped.

A classic "state machine". Your states are:

IDLE
STARTING
GOING_FORWARD
PAUSING
GOING_BACK

if the emergency reset button is pushed (goers from HIGH to LOW) in ANY state then you stop the train, put it in rverse, and move to GOING_BACK state.

if the emergency reset button is not pushed, then:

in IDLE state, if the button is pushed then you start sounding the soundtrack and go to STARTING state.

In STARTING state, if it has been X seconds since the start of the starting state then turn the horn off, turn forward on, and enter GOING_FORWARD state

In GOING_FORWARD state, if you hit the bumper then turn off the train and enter PAUSING state

In PAUSING state, if the pause has completed then pt the engine in reverse and enter GOING_BACK state

In GOING_BACK state, if you hit the other bumper then turn the engine off and enter IDLE state.

HI Paul

thanks that is exactly what I was looking for!!
I will read, learn, test and report.

beninflux:
HI Paul

thanks that is exactly what I was looking for!!
I will read, learn, test and report.

The pattern is:

// define a type for our states

enum State {
IDLE,
STARTING,
GOING_FORWARD,
PAUSING,
GOING_BACK
};

// create a variable holding the current state

State state = IDLE;

// the loop just does a time slice without delay

void loop() {
  // read the button.

  if( /* the button has just been pressed */ ) {
    // do the emergency stop stuff;
  }  
  else {
    switch(state) {
    case IDLE:
      // do whtever we need to do for IDLE
      if(/* something has happened that we need to respond to (button press) */ ) {
        /* do some stuff, which may involve entering another state*/
        sound hormn;
        start horn tmer;
        state = STARTING;
      }
      break;

    case STARTING:
      // do whtever we need to do for STARTING
      if(/* something has happened that we need to respond to - horn timeout*/ ) {
        /* do some stuff, which may involve entering another state */
        stop horn;
        start motor;
        state = GOING_FORWARD;
      }
      break;

    case GOING_FORWARD:
      // do whtever we need to do for GOING_FORWARD
      break;

    // etc, etc.
    }
  }
}

Note that we don't have delays or while() statments in the code. the "starting" case block detects when the start time has timed out, does whatever needs to be done to enter 'going forward' state, and then exits. The next execution of loop() will do the going_forward block.

This means that your loop() can do other things as well. For instance, if you have flashy lights, there might be a bit of code to manage the flashing. The state machine doesn't hang up and delay - it just breifly determines if it needs to do anything in respose to events that might have happened, and then continues on.

hi Paul

thanks a million times..
I am back at it tomorrow and cannot wait to test out the new code.