Gleisbesetztanzeige mit LDR

Mai 2020, Hurra es geht schonwieder weiter mit der Gleisbesetztanzeigerei. Ich wußte gar nicht mehr, daß ich noch LDRs im Bastelkisterl hab. Das passiert normalerweise nur dem Weib, wenns irgendwelches Gwamst aus ihrem schwarzen Loch (a.k.a. Kleider Kasten) hervorzaubert und meint: "Da schau her, ich wußte gar nicht, daß ich das hab".

Naja jedenfalls hab ich mich über 3 wundervolle, nagelneue LDRs gefreut und gleich mal was zusammengebastelt. Auf dem Sackl ist nur A9060 draufgestanden, das exakte Modell kann ich nicht mehr sagen.

 

LDR - Hä?

Für die Unwissenden, Light Dependent Resistor oder auch Fotowiderstand. Näheres siehe https://de.wikipedia.org/wiki/Fotowiderstand

LDR Schaltung

Hier die Schaltung, ähnlich zur IR Lichtschranke, nur halt ohne Sender. Der Sender ist quasi das Umgebungslicht. Habs spaßhalber mit zwei LDRs aufgebaut. Der LDR fungiert mit einem 100k Widerstand als Spannungsteiler und je nach Lichteinfall wird die Spannung von einem Analogport des Arduino gemessen. Die AnzeigeLEDs mit je 1k Vorwiderstand sind eh schon alter Hut.

Das Arduino Modell ist relativ blunzn, ich hab einen Nano genommen, aber auch Uno und dergleichen sind ok. Für eine Betriebsspannung von 3,3V (z.B. Due) müßt ma halt die Vorwiderstände der AnzeigeLEDs anpassen, fürn LDR- Spannungsteiler bleibt sichs wurscht.

 

Auch der Sketch ist relativ ähnlich dem von der IR Lichtschranke. Mit der genialen Erweiterung der Autokalibrier- Funktion. In der Setup Routine wird einfach der aktuelle Lichtwert gemessen und als Referenz- bzw. Schwellwert herangezogen.

 

Sketch

/*
  LDR track occupancy detector - for track occupied signal for a model railway
  provided from www.kraweuschuasta.at without any warranty or license 2020
  for personal use only

  Array used for more LDRs, LOW Signal = Active
  One Set per Track necessary (1x LDR Analogue Input, 2x indicator LED Digital Output)

  LDR autocalibration feature = while setup routine LDR average is calculaked and used as Threshold
  If ambient light is changed heavily it might be necessary to reset Arduino to force new LDR autocalibration.

  tested successfully on NANO (5V operating voltage)

  Schematic (example with 2 Sensors for 2 Tracks) ========================

  Light Dependent Resistor (Analog input!)
  VCC----100k----LDR0-------GND
               |
               Arduino (A2)

  VCC----100k----LDR1-------GND
               |
               Arduino (A3)

  INDICATOR LEDs
  VCC----1k----red LED-------(Arduino (2)
  VCC----1k----green LED-----(Arduino (3)

  VCC----1k----red LED-------(Arduino (4)
  VCC----1k----green LED-----(Arduino (5)
  Schematic End ===========================================================
*/
// ================ INIT section starts here ==========================
byte Red_Led[] = {2, 4};                           //Red indicator LED Array
byte GreenLed[] = {3, 5};                          //Green indicator LED Array
byte LDR_IN_Pin[] = {A2, A3};                      //LDR ANALOGUE input Array !!!
int Indicator_interval[] = {1000, 1000};           //interval in milliseconds that indicator LEDs are on (can be set for each Sensor Set red/green)
long lngserial_display_interval = 500;             //interval in milliseconds for Serial Monitor output (parametizing and debugging only)
// ================ INIT section END ==================================
byte i;                                                              //Counter variable, internal
byte avg_counter;                                                    //Counter variable for average value check, internal
int LDR_Invalue[(sizeof(LDR_IN_Pin) / sizeof(LDR_IN_Pin[0]))];       //Array for Sensor values
long lastmillis4serialprintln;                                       //variable to keep timestamp for Serial monitor (delay() replacement)
long LastMillis[(sizeof(LDR_IN_Pin) / sizeof(LDR_IN_Pin[0]))];       //Array to keep timestamp for indicator duration (delay() replacement)
int Triggervalue[(sizeof(LDR_IN_Pin) / sizeof(LDR_IN_Pin[0]))];      //Triggervalue for LDR - occupied or not
int intIRtotal, intLDRaverage  = 0;                                  //sum for average calculation for triggervalue, internal

void setup() {
  Serial.begin(9600);
  Serial.println("Arr_Size = " + String((sizeof(LDR_IN_Pin) / sizeof(LDR_IN_Pin[0])))); //Debug output
  Serial.println("Setup started.");

  for (byte i = 0; i < (sizeof(LDR_IN_Pin) / sizeof(LDR_IN_Pin[0])); i++) {             //Loop for declaring input/output + test Indicator LEDs
    //every led set is switched on for 500ms
    pinMode(Red_Led[i], OUTPUT);
    pinMode(GreenLed[i], OUTPUT);
    pinMode(LDR_IN_Pin[i], INPUT);
    digitalWrite(Red_Led[i], LOW);
    digitalWrite(GreenLed[i], LOW);
    Serial.println("LED Test started for Led " + String(i));
    delay (500);
  }

  for (byte i = 0; i < (sizeof(LDR_IN_Pin) / sizeof(LDR_IN_Pin[0])); i++) {             //set all Indicator LEDs to off
    digitalWrite(Red_Led[i], HIGH);
    digitalWrite(GreenLed[i], HIGH);

    intIRtotal = 0;                                                                     // get average value for LDR  (100 iterations)
    for (avg_counter = 0; avg_counter <= 100; avg_counter++)  {
      LDR_Invalue[i] = analogRead(LDR_IN_Pin[i]);
      intIRtotal = intIRtotal + LDR_Invalue[i];
      intLDRaverage = (intIRtotal / avg_counter);
    }
    Serial.println("average for Sensor " + String(i) + "  " + String(intLDRaverage));
    intLDRaverage = intLDRaverage + 10;                                                 // set Trigger value = average + 10
    Serial.println("Threshold for Sensor " + String(i) + " set to " + String(intLDRaverage));

    Triggervalue[i] = intLDRaverage;

    LastMillis[i] = millis();                                                     // update last millis for correct time calculations
  }

  Serial.println("Setup done.");
}

void loop() {

  if (lastmillis4serialprintln > millis() ) {                                     //  if millis() is restarted - re-set lastmillis timestamp
    lastmillis4serialprintln = millis();
    for (byte i = 0; i < (sizeof(LDR_IN_Pin) / sizeof(LDR_IN_Pin[0])); i++) {
      LastMillis[i] = millis();
    }
  }

  for (byte i = 0; i < (sizeof(LDR_IN_Pin) / sizeof(LDR_IN_Pin[0])); i++) {       //  loop thru Array for every LDR

    LDR_Invalue[i] = analogRead(LDR_IN_Pin[i]);                                   //  read values from Sensor into Array

    if (millis() - lastmillis4serialprintln >= lngserial_display_interval) {      //  check duration and write Value to Serial Monitor
      Serial.println("LDR " + String(i) + " Value: " + String(LDR_Invalue[i]));
      lastmillis4serialprintln = millis();                                        //  re-set last timestamp memory
    }

    if (LDR_Invalue[i] > Triggervalue[i] ) {                                      //  LDR is triggered?
      Serial.println("Triggered -- Sensor " + String(i));
      digitalWrite(Red_Led[i], LOW);                                              //  Indicator RedLeds are switched on
      digitalWrite(GreenLed[i], HIGH);                                            //  Indicator GreenLeds are switched off

    } else {                                                                      //  if not (no Train on Track)
      if ((LastMillis[i] + Indicator_interval[i]) <= (millis())) {
        digitalWrite(Red_Led[i], HIGH);                                           //  Indicator RedLeds are switched off
        digitalWrite(GreenLed[i], LOW);                                           //  Indicator GreenLeds are switched on
        LastMillis[i] = millis();                                                 //  re-set last timestamp memory
      }
    }
  }
}


Easy Cheesy Erweiterung

Der Sketch ist wieder unter Verwendung von Arrays aufgebaut, damit mans recht einfach erweitern kann. Einfach in die relevanten Arrays die hinzugekommenen LED Ports eintragen, neu kompilieren & auf den Arduino schießen.

 

Testaufbau

Und hier ist die Teststrecke. Ich hatte leider nicht die Zeit, Hill Valley maßstäblich dazu aufzubauen und anzumalen, tut mir leid.

Die LDRs passen bei H0 super über eine Schwelle, ohne Lokomotiven zu behindern, beim fliegenden Aufbau stehens bissl auf, bei einer fixen Anlage müsste mans ankleben.

 

Pauline gibt uns wieder die Ehre und fährt testhalber über die LDRs.

 

Pauline in Action

Weil die Pauline so hübsch ist, hier ein Video vom Test. Und natürlich, damit man die Gleisbesetztmeldung besser sehen kann.

 

Fazit

Gleisbelegtanzeige mit LDR ist gar keine schlechte Alternative, allerdings habe ich sie nicht bei grober Finsternis getestet.

Vorteile: Einfacher Aufbau, kleine Größe, geringer Preis

Nachteile: Funktioniert nicht im Dunklen, bei Änderung der Lichtverhältnisse (z.B. Licht einschalten) muss der Arduino neu kalibriert bzw. resettet werden

Zurück auf die Eisenbahnelektronikseite