Tenzij je in de rechter BB van je linker buurman/vouw een uitschuifbare set lichtsensoren monteert zodat de in/uitrij tijd iets verlengt kan worden...
Ik denk dat het grootste probleem het uitschakelen van de AKI wordt.
Waarom INPUT_PULLUP in plaats van INPUT. Edsko gaat werken met straal breking. Dit betekend dat de pen van de uitgang altijd laag is, tenzij er een trein de straal onderbreekt. Als extra beveiliging gebruik ik de INPUT_PULLUP, zodat bij draadbreuk tussen sensor en Arduino de Ardiono een bezette sensor ziet. Dit heeft bij reflectie geen zin en kan zelfs tot misvattingen leiden.@Meino: Er is nog een verschil. Ik heb 30 jaar bij de NS (waaronder Movares) gewerkt. Je krijgt dan tussen je oren gestampt dat een fout in de software mensenlevens kan kosten. Dus veel code en hardware ontwerpen hebben dit nog steeds als achtergrond. Ik ben onbewust altijd opzoek naar passieve beveiligingen.
#define DEBUG 0enum SpoorState {leeg, sensor1komend, sensor2komend, sensor1gaand, sensor2gaand };//// Class for a single (white) led which flickers 50 times per// minute when on//class SingleLed{ private: int ledPin; bool ledOn = true; int interval = 600; // *** 50 keer per minuut bool lightOn = false; unsigned long lastTime; public: // // Create a new instance of a (white) led, connect it to the specified // digital pin and put it in the specified state (true = on, false = off) // SingleLed(int aPin, bool state) { ledPin = aPin; ledOn = state; lightOn = false; pinMode(ledPin, OUTPUT); lastTime = millis(); } // // Set the state of the led (true = on, false = off) // void setOn(bool state) {#if (DEBUG) if (ledOn != state) { Serial.print("[SingleLed::setOn]"); if (state) Serial.println(" aan"); else Serial.println(" uit"); }#endif ledOn = state; } // // If the state is on, put power on the pin of the led, using timers // to make the flicker work. // If the led is off, remove the power from the pin of the led. // void heartBeat() { if (ledOn) // Do we need to light the led? { unsigned long currTime = millis(); if ((currTime - lastTime) >= interval) // Has the interval time passed? { lastTime = currTime; // Start new interval if (!lightOn) // Was the led lighted? {#if (DEBUG) Serial.println("[SingleLed::heartBeat] led aan");#endif digitalWrite(ledPin, HIGH); // No, so switch it on lightOn = true; } else {#if (DEBUG) Serial.println("[SingleLed::heartBeat] led uit");#endif digitalWrite(ledPin, LOW); // Yes, so switch it off lightOn = false; } } } else if (lightOn) // No light, but is the led still on? {#if (DEBUG) Serial.println("[SingleLed::heartBeat] led uit");#endif digitalWrite(ledPin, LOW); // Switch ir off lightOn = false; } }};//// Class for a set of two (red) leds which alternate(flicker) 50 times per// minute when on//class DuoLed{ private: int led1Pin; int led2Pin; bool ledOn = true; int interval = 600; // *** 50 keer per minuut bool lightOn = false; bool phase = false; unsigned long lastTime; public: // // Create a new instance, connect it to the specified // digital pins and put it in the specified state (true = on, false = off) // DuoLed(int aPin1, int aPin2, bool state) { led1Pin = aPin1; led2Pin = aPin2; ledOn = state; lightOn = false; phase = false; pinMode(led1Pin, OUTPUT); pinMode(led2Pin, OUTPUT); lastTime = millis(); } // // Set the state of the leds (true = on, false = off) // void setOn(bool state) {#if (DEBUG) if (ledOn != state) { Serial.print("[DuoLed::setOn]"); if (state) Serial.println(" aan"); else Serial.println(" uit"); }#endif ledOn = state; } // // If the state is on, put power on the pins of the leds, using timers // to make the alternating flicker work. // If the led is off, remove the power from the pins of the leds. // void heartBeat() { if (ledOn) // Are the leds activated { lightOn = true; unsigned long currTime = millis(); if ((currTime - lastTime) >= interval) // Has the interval passed? { lastTime = currTime; // Yes, start new interval if (!phase) // The leds alternate, are we in phase1 (led1 on, led2 off) {#if (DEBUG) Serial.println("[DuoLed::heartBeat] led1 aan, led2 uit");#endif digitalWrite(led1Pin, HIGH); // Yes, led1 on digitalWrite(led2Pin, LOW); // led2 off phase = true; // When the interval expires, switch the leds } else // We are in phase2 (led1 off, led2 on) {#if (DEBUG) Serial.println("[DuoLed::heartBeat] led1 uit, led2 aan");#endif digitalWrite(led1Pin, LOW); // Led1 off digitalWrite(led2Pin, HIGH); // Led2 on phase = false; // When the interval expires, switc the leds } } } else // The leds are not active, switch of both leds { if (lightOn) {#if (DEBUG) Serial.println("[DuoLed::heartBeat] led1 uit, led2 uit");#endif digitalWrite(led1Pin, LOW); digitalWrite(led2Pin, LOW); lightOn = false; } } }};enum AkiStaat {aan, uit};//// A simple class that represents a complet AKI with all its leds//// TBD, the sound of the bells//class AKI{ private: SingleLed *whiteLight; DuoLed *redLights; AkiStaat state = uit; public: // // Create an instance of the AKI, using the specified Led objects // AKI(SingleLed *aWhiteLed, DuoLed *aRedLed) { whiteLight = aWhiteLed; redLights = aRedLed; state = uit; } // // Activate the connected leds. TBD: the sound // void heartBeat() { redLights->heartBeat(); whiteLight->heartBeat(); } void set(AkiStaat aState) {#if (DEBUG) if (state != aState) { Serial.print("[AKI::set]"); if (aState == uit) Serial.println(" uit"); else Serial.println(" aan"); }#endif state = aState; if (state == uit) { redLights->setOn(false); whiteLight->setOn(true); } else { redLights->setOn(true); whiteLight->setOn(false); } }};//// Some sensors use a digital signal and keep it high when not active and drop the signal// when the sensor trips, use in that case the "laag" setting. Others use a digital signal// and are low when not active and make the signal high when the sensor trips, use in that case// the "hoog" setting.// if the sensor doesn't generate a digital signal, you have to use a pullup resistor (or INPUT_PULLUP)// and in that case specify hoog.//// The Flying Fish proximity detectors, when used in reflective mode, need the "laag" setting, // when their sensors are removed and positioned opposit each other, they need the "hoog" setting//enum SensorTrigger {laag, hoog};//// A simple class which represents the state of a single sensor//class Sensor{ private: int sensorPin; SensorTrigger type = hoog; bool state = false; // true = on, false = off unsigned long lastTime = 0; // Timer to ignore short interrupts#define JITTER_TIME 1000 // wait a second before the sensor goes off public: // // Create a new instance // Sensor(int aPin) { sensorPin = aPin; pinMode(sensorPin, INPUT); } // // Create a new instance // Sensor(int aPin, SensorTrigger aType) { sensorPin = aPin; type = aType; pinMode(sensorPin, INPUT); } // // Return the current logical state of the sensor // bool getState() { return state; } // // Monitor the physical sensor and update the state accordingly // void heartBeat() { if (digitalRead(sensorPin) == HIGH) { if (type == laag) // For sensors type laag an high signal means they are in the off state { if (state != false) // Process this signal only when the current state is ON { if (lastTime == 0) { lastTime = millis(); // start Interval } else { unsigned long currTime = millis(); if ((currTime - lastTime) >= JITTER_TIME) {#if (DEBUG) Serial.println("[Sensor::heartBeat] sensor(laag) goes off");#endif state = false; // sensor goes OFF lastTime = 0; // Reset interval timer } } } } else {#if (DEBUG) if (state != true) { Serial.println("[Sensor::heartBeat] sensor(hoog) goes on"); }#endif state = true; // Sensor goes ON lastTime = 0; // Reset interval timer } } else // sensorPin = LOW { if (type == laag) {#if (DEBUG) if (state != true) { Serial.println("[Sensor::heartBeat] sensor(laag) goes on"); }#endif state = true; // Sensor goes ON lastTime = 0; // Reset interval timer; } else { if (state != false) // Process this signal only when the current state is ON { if (lastTime == 0) { lastTime = millis(); // start Interval } else { unsigned long currTime = millis(); if ((currTime - lastTime) >= JITTER_TIME) {#if (DEBUG) Serial.println("[Sensor::heartBeat] sensor(hoog) goes off");#endif state = false; // sensor goes OFF lastTime = 0; // Reset interval timer } } } } } }};//// A finite state machine that guards a occupance of a single track//class SpoorControl{ private: Sensor *sensor1; Sensor *sensor2; SpoorState state = leeg; // // Based on the state of sensor 1 and the current state of the FSM, a new state // is calculated. // void handleSensor1(bool trigger) { if (trigger) // Sensor 1 is ON { if (state == leeg) // If the state is "leeg" it means that a train enters the section {#if (DEBUG) Serial.println("[SpoorControl::handleSensor1] state is sensor1komend");#endif state = sensor1komend; // so set it to state komend } else if (state == sensor2komend) // if the other sensor tripped first {#if (DEBUG) Serial.println("[SpoorControl::handleSensor1] state is sensor1gaand");#endif state = sensor1gaand; // The train is starting to leave the section } } else { // Sensor went OFF if (state == sensor1gaand) // If the train started to leave via sensor 1 {#if (DEBUG) Serial.println("[SpoorControl::handleSensor1] state is leeg");#endif state = leeg; // the section is "leeg" } } } // // Based on the state of sensor 2 and the current state of the FSM, a new state // is calculated. // void handleSensor2(bool trigger) { if (trigger) // Sensor 2 is ON { if (state == leeg) // Is the section "leeg"? {#if (DEBUG) Serial.println("[SpoorControl::handleSensor2] state is sensor2komend");#endif state = sensor2komend; // A Train entered the section via sensor 2 } else if (state == sensor1komend) // No a train entered the section via the other sensor {#if (DEBUG) Serial.println("[SpoorControl::handleSensor2] state is sensor2gaand");#endif state = sensor2gaand; // Start the leaving process } } else { if (state == sensor2gaand) // A train is in the process of leaving {#if (DEBUG) Serial.println("[SpoorControl::handleSensor2] state is leeg");#endif state = leeg; // Section is empty again } } } public: // // Create an instance with two sensors // SpoorControl(Sensor *aSensor1, Sensor *aSensor2) { sensor1 = aSensor1; sensor2 = aSensor2; } // // Get give the sensors a kick and check their state so we can update our own // state. // void heartBeat() { sensor1->heartBeat(); sensor2->heartBeat(); handleSensor1(sensor1->getState()); handleSensor2(sensor2->getState()); } // // Return the current state of the section // SpoorState getState() { return state; }};//// Create 2 FSM controling two track sections//SpoorControl spoor1(new Sensor(A0, laag), new Sensor(A1, laag)); // Sensor works reflectiveSpoorControl spoor2(new Sensor(A2, laag), new Sensor(A3, laag));//// Create an instance of the AKI//AKI aki(new SingleLed(A4, true), new DuoLed(A5, A6, false));void setup(){#if (DEBUG) //Serial.begin(9600); Serial.begin(115200); while (!Serial); Serial.println("Starting"); Serial.flush();#endif //DEBUG}void loop(){ spoor1.heartBeat(); // These object must monitor their sensors spoor2.heartBeat(); // so they can update their states if ((spoor1.getState() == leeg) && (spoor2.getState() == leeg)) { aki.set(uit); // Stop sound and flashing red lights } else { aki.set(aan); // Start flashing red lights and sound } aki.heartBeat(); // Let the AKI update it's connected bells and leds}
Wat gebeurt er als een (korte) trein helemaal tussen twee lichtsluizen past? Op dat moment melden beide 'laag' en dan zou de aki open gaan, terwijl er een trein overheen rijdt.