Skip to content
This repository has been archived by the owner on Mar 1, 2024. It is now read-only.

Commit

Permalink
Update RailCrossing.ino
Browse files Browse the repository at this point in the history
  • Loading branch information
cotestatnt authored Jul 27, 2022
1 parent 14a7637 commit e3a222f
Showing 1 changed file with 96 additions and 78 deletions.
174 changes: 96 additions & 78 deletions examples/RailCrossing/RailCrossing.ino
Original file line number Diff line number Diff line change
@@ -1,123 +1,141 @@
#include <YA_FSM.h>
#include <Servo.h>
#include "YA_FSM.h"
#include "Blinker.h"

const byte SIG_TRAIN_IN = 2;
const byte SIG_TRAIN_OUT = 3;
#define SIG_TRAIN_IN 3
#define SIG_TRAIN_OUT 2
#define SERVO_PIN 6

const byte OUT_BAR_LOW = 11;
const byte OUT_BAR_HIGH = 12;
const byte OUT_LIGHT_BELL = 13;
#define PASS_NOT_ALLOWED 11
#define PASS_ALLOWED 12
#define OUT_LIGHT_BELL 13

// After the train has passed, wait a little time to be sure
#define MOVE_TIME 1000 // Time needed for GATE moving (up and down)
#define WAIT_FREE 10000 // Wait time after train has gone (in case another train is arriving)
#define BLINK_TIME 250

#define GATE_CLOSED 0
#define GATE_OPENED 90

// Create new FSM
YA_FSM stateMachine;

// Create a Blinker (included utility class) for led blink handling
Blinker blinker(OUT_LIGHT_BELL, BLINK_TIME);

// Handle the gate position
Servo theGate;
uint16_t servoPos = GATE_OPENED;

// State Alias
enum State {GATE_OPEN, GATE_LOWERING, GATE_CLOSE, GATE_WAIT, GATE_RISING };

// Helper for print labels instead integer when state change
const char* const stateName[] PROGMEM = { "Gate OPEN", "Lowering GATE", "Gate CLOSE", "Wait time", "Rising GATE"};

// After the train has passed, wait a little time to be sure
#define MOVE_TIME 5000 // Time needed for GATE moving (up and down)
#define WAIT_FREE 15000
#define BLINK_TIME 250

// Instead of bool function() callback, in this example we will use
// bool variables to trig two transitions (the others will trig on timout)
bool theTrainIsComing = false;
bool theTrainIsGone = false;

void setup() {
// Input/Output configuration
pinMode(SIG_TRAIN_IN, INPUT_PULLUP);
pinMode(SIG_TRAIN_OUT, INPUT_PULLUP);
pinMode(OUT_BAR_LOW, OUTPUT);
pinMode(OUT_BAR_HIGH, OUTPUT);
pinMode(OUT_LIGHT_BELL, OUTPUT);

Serial.begin(115200);
while (!Serial) { ; } // Wait for serial to be ready (native USB board only)

Serial.println(F("Starting State Machine...\n"));
setupStateMachine();

onEnter(); // Call manually the onEnter() function to set outputs
Serial.print(F("Active state: "));
Serial.println(stateMachine.ActiveStateName());
}

void loop() {
// Update State Machine
stateMachine.Update();

// Update the bool variables according to the signal inputs
theTrainIsGone = digitalRead(SIG_TRAIN_OUT) == LOW;
theTrainIsComing = digitalRead(SIG_TRAIN_IN) == LOW;

if (theTrainIsComing) {
// Reset enter time of GATE_WAIT (if active) so timeout became
// longer enough to wait two ore more trains one after the other
stateMachine.SetEnteringTime(GATE_WAIT);
}
}


// Define "on entering" callback function (the same for all states)
void onEnter(){
void onEnter(){
switch (stateMachine.GetState() ){
case GATE_CLOSE:
digitalWrite(OUT_BAR_LOW, HIGH);
digitalWrite(PASS_NOT_ALLOWED, HIGH);
Serial.println(F("The GATE is actually close"));
break;
case GATE_RISING:
digitalWrite(OUT_BAR_LOW, LOW);
case GATE_RISING:
servoPos = GATE_OPENED;
digitalWrite(OUT_LIGHT_BELL, LOW);
Serial.println(F("The GATE is going to be opened"));
break;
case GATE_OPEN:
digitalWrite(OUT_BAR_HIGH, HIGH);
digitalWrite(PASS_NOT_ALLOWED, LOW);
digitalWrite(PASS_ALLOWED, HIGH);
Serial.println(F("The GATE is actually open"));
break;
case GATE_LOWERING:
digitalWrite(OUT_BAR_HIGH, LOW);
servoPos = GATE_CLOSED;
digitalWrite(PASS_ALLOWED, LOW);
digitalWrite(PASS_NOT_ALLOWED, HIGH);
Serial.println(F("A new train is coming! Start closing the GATE."));
Serial.println(F("The GATE is going to be closed"));
break;
case GATE_WAIT:
Serial.println(F("The GATE is stille closed and we have to wait a little"));
Serial.println(F("Train passed, but we have to wait a little time more"));
break;
}
}

// Blink and play the bell while gate is moving or closed
void onStateMoveOpen(){
static uint32_t bTime;
if(millis() - bTime > BLINK_TIME) {
bTime = millis();
digitalWrite(OUT_LIGHT_BELL, !digitalRead(OUT_LIGHT_BELL));
}
// Blink and play the bell while gate is moving or closed
void blinkAndHorn(){
blinker.blink(true);
}


// Setup the State Machine
void setupStateMachine() {

/*
* Follow the order of enumeration for the state definition, if used.
* Index of states will be increased in library on every AddState()
* In this way, enumerated index of skecth will match the library index.
void setupStateMachine() {
/*
Follow the order of defined enumeration for the state definition (will be used as index)
You can add the states with 3 different overrides:
Add States => name, timeout, minTime, onEnter cb, onState cb, onLeave cb
Add States => name, timeout, onEnter cb, onState cb, onLeave cb
Add States => name, onEnter cb, onState cb, onLeave cb
*/

// Add States => name,timeout, onEnter cb, onState cb, onLeave cb
stateMachine.AddState(stateName[GATE_OPEN], 0, onEnter, nullptr, nullptr);
stateMachine.AddState(stateName[GATE_LOWERING], MOVE_TIME, onEnter, onStateMoveOpen, nullptr);
stateMachine.AddState(stateName[GATE_CLOSE], 0, onEnter, onStateMoveOpen, nullptr);
stateMachine.AddState(stateName[GATE_WAIT], WAIT_FREE, onEnter, onStateMoveOpen, nullptr);
stateMachine.AddState(stateName[GATE_RISING], MOVE_TIME, onEnter, onStateMoveOpen, nullptr);
stateMachine.AddState(stateName[GATE_OPEN], onEnter, nullptr, nullptr);
stateMachine.AddState(stateName[GATE_LOWERING], MOVE_TIME, onEnter, blinkAndHorn, nullptr);
stateMachine.AddState(stateName[GATE_CLOSE], onEnter, blinkAndHorn, nullptr);
stateMachine.AddState(stateName[GATE_WAIT], WAIT_FREE, onEnter, blinkAndHorn, nullptr);
stateMachine.AddState(stateName[GATE_RISING], MOVE_TIME, onEnter, blinkAndHorn, nullptr);

// Add transitions with related trigger input callback functions
stateMachine.AddTransition(GATE_OPEN, GATE_LOWERING, theTrainIsComing);
stateMachine.AddTransition(GATE_LOWERING, GATE_CLOSE, [](){return stateMachine.CurrentState()->timeout;} );
stateMachine.AddTransition(GATE_CLOSE, GATE_WAIT, theTrainIsGone);
stateMachine.AddTransition(GATE_WAIT, GATE_RISING, [](){return stateMachine.CurrentState()->timeout;} );
stateMachine.AddTransition(GATE_RISING, GATE_OPEN, [](){return stateMachine.CurrentState()->timeout;} );
stateMachine.AddTransition(GATE_OPEN, GATE_LOWERING, theTrainIsComing);
stateMachine.AddTransition(GATE_CLOSE, GATE_WAIT, theTrainIsGone);

// Add "timed" transitions: it will be triggered on state timeout
stateMachine.AddTransition(GATE_LOWERING, GATE_CLOSE);
stateMachine.AddTransition(GATE_WAIT, GATE_RISING);
stateMachine.AddTransition(GATE_RISING, GATE_OPEN);
}


void setup() {
// Input/Output configuration
pinMode(SIG_TRAIN_IN, INPUT_PULLUP);
pinMode(SIG_TRAIN_OUT, INPUT_PULLUP);
pinMode(PASS_NOT_ALLOWED, OUTPUT);
pinMode(PASS_ALLOWED, OUTPUT);

Serial.begin(115200);
Serial.println(F("Starting State Machine...\n"));
setupStateMachine();

onEnter(); // Call first time the onEnter() function to set outputs
Serial.print(F("Active state: "));
Serial.println(stateMachine.ActiveStateName());

theGate.attach(SERVO_PIN);
}

void loop() {
theGate.write(servoPos);

// Update State Machine
stateMachine.Update();

// Update the bool variables according to the signal inputs
theTrainIsGone = digitalRead(SIG_TRAIN_OUT) == LOW;
theTrainIsComing = digitalRead(SIG_TRAIN_IN) == LOW;

if (theTrainIsComing) {
// Reset enter time of GATE_WAIT so timeout became longer enough
// to wait two ore more trains one after the other
stateMachine.SetEnteringTime(GATE_WAIT);
if (stateMachine.GetState() == GATE_WAIT ) {
delay(500);
Serial.println(F("Another train is arriving, wait more time!"));
}
}
}

0 comments on commit e3a222f

Please sign in to comment.