sitemap link mailform link home

SPURT-Lichtschranke

Beitrag vom 25. April 2019

Ziel und Konzept

Das Ziel dieses Projektes war es, eine transportable Lichtschranke für den SPURT-Roboterwettbewerb zu bauen. Dabei sollte die bereits vorhandene PC-Software auf Basis von Visual Basic (entwickelt von Steffen Prüter) weiterhin verwendet werden.

Hier im SPURT-Schülerlabor der Uni Rostock  ist eine Rennstrecke mit fest eingebauter Laser-Lichtschranke und PC-Anbindung über die serielle Schnittstelle vorhanden. Dabei war die punktgenaue Justierung des Laserstrahls jedoch immer ein Problem und führte zu Ausfällen.

Das vorgestellte Projekt basiert auf meiner selbst entwickelten IR-Lichtschranke.
Siehe auch:

 Interner Link http://elektronik.nmp24.de/index.php?Bauanleitungen:IR-Lichtschranke

Der Verwendung einer IR-Lichtschranke hat den Vorteil, dass der IR-Lichtstrahl nicht so stark gebündelt ist und daher nicht punktgenau auf den Empfänger (IR-Fototransistor) ausgerichtet und justiert werden muss. Außerdem ist die Anfälligkeit für Umgebungslicht bei Infrarot-Lichtschranken geringer. Auf eine Modulation des IR-Lichtstrahls kann daher verzichtet werden.
Die Begrenzung des IR-Lichtstrahls geschieht beim Empfänger (Fototransistor). Dieser Fototransistor sitzt am Ende einer 60 mm langen Bohrung mit 8 mm Durchmesser. Damit wird das Umgebungslicht fast vollständig ferngehalten. Allerdings: Direkt einfallendes Sonnenlicht würde die Lichtschranke auslösen. Da sich aber auf der gegenüber liegenden Seite die Traverse mit der IR-Fotodiode befindet, kann man davon ausgehen, dass keine Sonnenstrahlen beim Fototransistor ankommen.

Zusätzlich soll eine Zeitmessung (vollständig unabhängig vom Notebook) mittels eines Arduino UNO direkt auf der "Brücke" durchgeführt und auf einem LC-Display DEM16216 dargestellt werden.
So könnte auch bei einem hypothetischen Ausfall des Notebooks das Rennen fortgesetzt werden.

Durch die Verwendung des Arduino-Systemtaktes millis() wird eine sehr hohe Genauigkeit erreicht, so dass die "Notebook-Zeit" und die "Arduino-Zeit" nur einige Hundertstel Sekunden differieren.

Digitalpin 8 = Reset-Schalter (Schließer)
Digitalpin 9 = Relais-Kontakt der IR-Lichtschranke (Schließer)
Pin 8  und Pin 9 sind mit je einem 10-kΩ-Widerstand gegen Masse verbunden. Das ist ganz wichtig, da die Pins ansonsten bei geöffnetem Schalter bzw. Relaiskontakt "in der Luft hängen" und kein definiertes Potential besitzen.

Die IR-Lichtschranke

Stromlaufplan

Stückliste:

IR-LED (3 oder 5 mm) mit Infrarot 940 oder 950 nm (z.B. IR-LED SANKEN SID1050M
Pollin-Bestellnummer: 120038

Fototransistor (npn) TEMIC K153P (leider nicht mehr lieferbar)
Ersatz:Fototransistor 5 mm rund 940 nm 20 ° Lite-On LTR-3208 z.B. bei Conrad.de (ungetestet)

3 x Widerstand 10 kΩ
1 x Widerstand 220 kΩ
1 x Widerstand 330 Ω
1 x Elektrolytkondensator 100 oder 220 uF (mindestens 15 V)
2 x Diode mit 1 A Belastbarkeit (z.B. 1N5817 mit 20 V / 1 A)
3 x npn-Transistor BC337/25 oder BC337/40 oder BC548C...
1 x Relais Finder F4052-12
1 x Einstellregler 500 kΩ, z.B. PIHER PT-10 liegend
6 x Leiterplatten-Anschlussklemme, anreihbar, RM5 mm, Pollin-Bestellnummer 450856

PDF Datenblatt TEMIC K153P

Platine Bestückungsseite:

Bestückung


PDF Platine (2 Stück) als PDF auf A4 zum "Aufbügeln"

Zip-Ordner Schaltplan (CircScheme)
Zip-Ordner Platine (Sprint-Layout)

Arduino-Quellcode für eine zusätzliche Zeitanzeige auf einem handelsüblichen LC-Display:

// SPURT-Stoppuhr mit millis()-Systemtakt
#include LiquidCrystal.h // Die korrekten Klammern sind hier leider nicht darstellbar!!!!


#define RESETPIN 8
#define RELAISPIN 9
#define TOTZEIT 2000 // in Millisekunden -> nur ganze Sekunden einstellen
#define MAXZEIT 30 // Maximale Messzeit für einzelnes Rennen in Sekunden
unsigned long varTakt; // Wechselt zwischen 0 und 1 innerhalb einer Hundertstelsekunde
int varSekunden = 0;
int varHundertstel = 0;
bool varStarted = false;

const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

void setup() {
  lcd.begin(16, 2);
  lcd.print("SPURT-Stoppuhr");
  pinMode(RESETPIN, INPUT);
  pinMode(RELAISPIN, INPUT);
  delay(TOTZEIT);
  lcd.setCursor(0, 0);
  lcd.print("Bereit             ");
  ZeitausgabeLCD(0, 1, varSekunden, varHundertstel);
}

void loop() {
  bool varReset = digitalRead(RESETPIN);
  bool varRelais = digitalRead(RELAISPIN);
  // Nur ausführen, wenn das Rennen bereits gestartet wurde:
  if (varStarted == true)
  {
    varTakt = (millis() / 10 % 2); // Erzeugen des Taktes in Hundertstelsekunden
    while (varTakt == (millis() / 10 % 2)) {} // Verzögerung -> Warten auf neuen Takt!
    // Damit wird exakt alle 0,01 Sekunden hochgezählt:
    varHundertstel++;
    if (varHundertstel > 99)
    {
      varHundertstel = 0;
      varSekunden++;
      if (varSekunden == MAXZEIT)
      {
        varStarted = false;
        ZeitausgabeLCD(0, 1, varSekunden, varHundertstel);
        lcd.setCursor(0, 0);
        lcd.print("Maximale Zeit!  ");
        delay(TOTZEIT);
      }
    }
    if (varHundertstel % 10 == 0)
    {
      // Das LC-Display ist zu langsam...
      // Deshalb nur alle 0,1 Sekunden Zeitanzeige
      ZeitausgabeLCD(0, 1, varSekunden, varHundertstel);
    }
  }

  // Auswertung der Reset-Taste
  if (varReset == HIGH)
  {
    lcd.setCursor(0, 0);
    lcd.print("Reset             ");
    varHundertstel = 0;
    varSekunden = 0;
    ZeitausgabeLCD(0, 1, varSekunden, varHundertstel);
    delay(TOTZEIT);
    lcd.setCursor(0, 0);
    lcd.print("Bereit             ");
    varStarted = false;
  }

  // Auswertung des Relaiskontaktes der Lichtschranke:
  if (varRelais == HIGH)
  {
    // Falls das Rennen bereits lief -> Stopp
    if (varStarted == true)
    {
      varStarted = false; // Stopp-Signal für  Zeitmessung
      lcd.setCursor(0, 0);
      lcd.print("Aktuelle Zeit:   ");
      ZeitausgabeLCD(0, 1, varSekunden, varHundertstel);
      delay(TOTZEIT);
    }
    else
    {
      // Falls das Rennen noch nicht lief -> Start
      lcd.setCursor(0, 0);
      lcd.print("Gestartet        ");
      delay(TOTZEIT);
      // Die Totzeit verzögert den Timer-Start
      // Deshalb muss sie bei der Zeitmessung als Anfangswert verwendet werden:
      varSekunden = TOTZEIT / 1000;
      varStarted = true; // Start-Signal für Zeitmessung
    }
  }
}

void ZeitausgabeLCD(int spalte, int zeile, int sekunden, int hundertstel)
{
  lcd.setCursor(spalte, zeile);
  if (sekunden < 10) lcd.print("0");
  lcd.print(sekunden);
  lcd.print(":");
  if (hundertstel < 10) lcd.print("0");
  lcd.print(hundertstel);
  lcd.print("                ");
}

 

Verwendung eines 7-Segment-Displays 5641AH mit gemeinsamen Kathoden

Die Ziffern dieses Displays leuchten schön hell in Rot und sind auch aus einer Entfernung von 3 Metern noch gut erkennbar.

Das Display benötigt übrigens 12 Digitalpins, so dass gerade noch 2 Pins für den Reset-Taster und den Relaiskontakt übrig bleiben. Im Demo-Programm für die Bibliothek "SevSeg" werden daher die Pins 2 bis 13 für das Display verwendet.
Die Pins 0 und 1 des Arduino sind eigentlich für die serielle Datenkommunikation reserviert. Sie funktionierten bei meinen Tests nicht als digitaler Input für den Taster und das Relais.
Daher testete ich, ob sie als Ausgang für das Display funktionieren würden.
Das war zum Glück der Fall! Für das Display werden daher nun die Pins 0 und 1 sowie die Pins 4 bis 13 verwendet.

Die frei werdenden "normalen" Digital-Pins werden nun wie folgt als Eingänge (Inputs) verwendet:

Digitalpin 2 = Reset-Schalter (Schließer)
Digitalpin 3 = Relais-Kontakt der IR-Lichtschranke (Schließer)

Pin 2  und Pin 3 müssen auch hier wieder mit je einem 10-kΩ-Widerstand gegen Masse verbunden. Das ist ganz wichtig, da die Pins ansonsten bei geöffnetem Schalter bzw. Relaiskontakt "in der Luft hängen" und kein definiertes Potential besitzen.

Display 56451AH   5641AH Beschaltung

Weitere Details zur Funktion und Beschaltuing finden Sie hier:

Externer Link https://funduino.de/nr-12-7-segment-anzeige

Externer Link www.acoptex.com...

Arduino-Quellcode für eine zusätzliche Zeitanzeige mit 7-Segment-Anzeige:

// SPURT-Stoppuhr mit millis()-Systemtakt
// Verwendet wird eine 7-Segment-Anzeige vom Typ 5641AH

// ACHTUNG: Die Bibliotheken müssen in der Arduino IDE installiert werden!
#include "SevSeg.h" // Sieben-Segment-Library laden
#include "TimerOne.h" // Timer-Interrupt-Library für Zeitanzeige-Refresh laden
SevSeg sevseg; //Ein Sieben-Segment-Objekt initialisieren

#define RESETPIN 2 // externer Taster zum Rücksetzen der Messzeit auf 00:00
#define RELAISPIN 3 // Relaiskontakt (Schließer) der Lichtschranke
#define TOTZEIT 2000 // in Millisekunden -> nur ganze Sekunden einstellen
#define MAXZEIT 30 // Maximale Messzeit für einzelnes Rennen in Sekunden

int varSekunden = 0;
int varHundertstel = 0;
bool varStarted = false; // true = Rennen gestartet und läuft

void Zeitanzeige()
{
  int anzeige = 100 * varSekunden + varHundertstel;
  sevseg.setNumber(anzeige, 2); //Ausgabe von "anzeige" und Kommapunkt an Pos. "2"
  sevseg.refreshDisplay(); // Dieser Teil lädt die Nummer auf das Display
}

void setup() {
  byte numDigits = 4; //Anzahl der Stellen des Displays
  byte digitPins[] = {0, 1, 4, 5}; //Die Pins für die gemeinsamen Kathoden (oder Anoden)
  byte segmentPins[] = {6, 7, 8, 9, 10, 11, 12, 13}; //Die Pins der Segmente a bis g und Punkt
  sevseg.begin(COMMON_CATHODE, numDigits, digitPins, segmentPins);
  // Timer für Zeitanzeige-Interrupt
  Timer1.initialize(1 * 1000); // Takt für 7-Segment-Display = 1 Millisekunde
  Timer1.attachInterrupt(Zeitanzeige); // Interrupt Service Routine "Zeitanzeige"

  pinMode(RESETPIN, INPUT);
  pinMode(RELAISPIN, INPUT);
  delay(TOTZEIT);
}

void loop() {
  bool varReset = digitalRead(RESETPIN);
  bool varRelais = digitalRead(RELAISPIN);

  // Nur ausführen, wenn das Rennen bereits gestartet wurde:
  if (varStarted == true)
  {
    unsigned long varTakt = (millis() / 10 % 2); // Erzeugen des Taktes für die Hundertstelsekunden
    while (varTakt == (millis() / 10 % 2)) {} // Verzögerung -> Warten auf neuen Takt!
    // Damit wird nun exakt alle 0,01 Sekunden (Hundertstelsekunden) hochgezählt:
    varHundertstel++;
    if (varHundertstel > 99)
    {
      varHundertstel = 0;
      varSekunden++;
      if (varSekunden == MAXZEIT)
      {
        varStarted = false; // Zeitmessung endet...
        delay(TOTZEIT); // Zeitüberschreitung!
      }
    }
  }

  // Auswertung der Reset-Taste
  // Zeit auf 00:00 stellen:
  if (varReset == HIGH)
  {
    varHundertstel = 0;
    varSekunden = 0;
    delay(TOTZEIT);
    varStarted = false;
  }

  // Auswertung des Relaiskontaktes der Lichtschranke:
  if (varRelais == HIGH)
  {
    if (varStarted == true)
    {
      // Falls das Rennen bereits lief -> Stopp
      varStarted = false; // Stopp-Signal für  Zeitmessung
      delay(TOTZEIT);
    }
    else
    {
      // Falls das Rennen noch nicht lief -> Start
      delay(TOTZEIT); // Die Totzeit verzögert den Timer-Start
      // Deshalb muss sie bei der Zeitmessung als Anfangswert verwendet werden:
      varSekunden = TOTZEIT / 1000;
      varHundertstel = 0;
      varStarted = true; // Start-Signal für Zeitmessung
    }
  }
}

.

Letzte Änderung:
March 23. 2023 21:04:40
«    top    »