Go Down

Topic: bestimmter Sensor und/oder Hilfe gesucht (Read 1 time) previous topic - next topic

Hoplost

Haha,
Dankeschön. Das ist für Platzierung in den Gleisen etwas groß.

Ich habe mich etwas in die 125khz-Tematk eingelesen und jetzt auch ein rdm6300-Modul hier zum testen.
Ich habe auch das hier im Forum gefunden
https://forum.arduino.cc/index.php?topic=145244.0
Im vierten Beitrag ist ein Demo-Sketch von "jurs".
Ich habe diesen hier nur leicht modifiziert um mein jetziges Problem darzustellen.
Code: [Select]

// RFID demo sketch by "jurs" for Arduino Forum Deutsch

// start text character
#define STX 2
// end text character
#define ETX 3

// buffer to hold the last code read from Serial
char rfidBufferLastRead[13];

boolean readRFID()
{
  if (!Serial.available()) return(false); // nothing available to read
  char rfidBuffer[13];
  char c=0;
  int i=0;
  memset(rfidBuffer,0,sizeof(rfidBuffer)); // clear receive buffer
  delay(50); // wait for code to appear in the Serial input buffer
  while (Serial.available()&& c!=STX) // watch out for start of text character
    c=Serial.read();
  while (Serial.available()&& i<12 && c!=ETX) // watch out for end of text character
  {
    c=Serial.read();
    rfidBuffer[i] = c;
    i++;
  }
  if (i!=12) return(false); // less than 12 characters read from Serial
  if (Serial.available()) c=Serial.read();
  if (c!=ETX) return(false);
  strncpy(rfidBufferLastRead,rfidBuffer,sizeof(rfidBuffer)); // copy into global variable rfidBufferLastRead
  return(true); // if we reach this line, we have read 12 digits from Serial
}


void setup()
{
  Serial.begin(9600);
  Serial.println("waiting for RFID...");
}

void loop()
{
  if (readRFID())
  {
    if (strcmp(rfidBufferLastRead,"6C00679D1F89")==0)
        {
        Serial.println("lok 1");
        delay(3000);      //Hier eine zusätzliche Wartezeit
        }
    else if (strcmp(rfidBufferLastRead,"123456789012")==0)
      Serial.println("Hello Bill!");
    else if (strcmp(rfidBufferLastRead,"800C4C028042")==0)
      Serial.println("Hello Bob!");
    else
    {
      Serial.print("Fuck off! "); 
      Serial.println(rfidBufferLastRead);
    } 
  }
}


Im loop-Bereich wird mein rfid-Tag erkannt und ich habe ein relay von 3 Sekunden eingefügt.
Wenn ich das Programm starte und Tag rund ein bis zwei Sekunden an die Antenne halte wird dieser erkannt. Der Text erscheint im Seriellen Monitor und nach drei Sekunden eben noch einmal ... und noch einmal ... und noch einmal. Bis das sieben oder acht mal erschienen ist. Das dauert so knapp 20 Sekunden.

Wenn ich statt des delay ein Relais ansteuerte, das zum Beispiel für eine Minute einen Stromfluss unterbrechen soll, wird das auch mehrmals ausgelöst.

Ich möchte gerne das Relais nur einmal auslösen und erst wenn der Tag wieder im Eingangsbereich ist ein weiteres mal.
Ich hoffe ich habe mich verständlich ausgedrückt.

gregorss

... Wenn ich statt des delay ein Relais ansteuerte ...
Was ist in diesem Zusammenhang ein Delay, wenn es kein Relais mit Tippfehler ist?!

Gruß

Gregor
„Ich glaube, ich leg' mich noch mal hin", sagte das Bit.

Hoplost

Hallo Gregor,
Das war, von mir, schlecht dargestellt.

In dem geposteten Beispielcode nutze ich den delay-Befehl um es anschaulich darzustellen.

Auf meiner Modellbahn soll bei erkennen des richtigen rfid-Tag, also der richtigen Lok, nach einer Verzögerung die Stromzufuhr, für rund eine Minute, unterbrochen werden um ein Pendelbetrieb für eine andere Lok auszulösen. Im Beispielcode sähe das dann ungefähr so aus.

Code: [Select]


// RFID demo sketch by "jurs" for Arduino Forum Deutsch

// start text character
#define STX 2
// end text character
#define ETX 3

int relaisPin = 5;

// buffer to hold the last code read from Serial
char rfidBufferLastRead[13];

boolean readRFID()
{
  if (!Serial.available()) return(false); // nothing available to read
  char rfidBuffer[13];
  char c=0;
  int i=0;
  memset(rfidBuffer,0,sizeof(rfidBuffer)); // clear receive buffer
  delay(50); // wait for code to appear in the Serial input buffer
  while (Serial.available()&& c!=STX) // watch out for start of text character
    c=Serial.read();
  while (Serial.available()&& i<12 && c!=ETX) // watch out for end of text character
  {
    c=Serial.read();
    rfidBuffer[i] = c;
    i++;
  }
  if (i!=12) return(false); // less than 12 characters read from Serial
  if (Serial.available()) c=Serial.read();
  if (c!=ETX) return(false);
  strncpy(rfidBufferLastRead,rfidBuffer,sizeof(rfidBuffer)); // copy into global variable rfidBufferLastRead
  return(true); // if we reach this line, we have read 12 digits from Serial
}


void setup()
{
  Serial.begin(9600);
  Serial.println("waiting for RFID...");
}

void loop()
{
  if (readRFID())
  {
    if (strcmp(rfidBufferLastRead,"6C00679D1F89")==0)
        {
        Serial.println("lok 1");
        delay(3000);      //Hier eine zusätzliche Wartezeit bis das Relais auslöst
        digitalWrite(relaisPin, HIGH); // Relais am Pin 5 auslösen
        delay(60000); // eine Minute warten
        digitalWrite(relaisPin, LOW);
        }
    else if (strcmp(rfidBufferLastRead,"123456789012")==0)
      Serial.println("Hello Bill!");
    else if (strcmp(rfidBufferLastRead,"800C4C028042")==0)
      Serial.println("Hello Bob!");
    else
    {
      Serial.print("Fuck off! ");
      Serial.println(rfidBufferLastRead);
    }
  }
}



Auch hier wird das Relais aber mehrmals angesprochen.
--> Ich halte den Tag an in den Empfangsbereich. Ein bis Zwei Sekunden
--> Der Tag wird, in dieser Zeit, mehrmals erkannt -- z.B. acht mal.
--> das Relais wird acht mal hintereinander ausgelöst.

Ich möchte einen RFID-Tag-Aufkleber unter die Lok kleben und die Antenne ins Gleisbett legen. Die Lok überfährt dann die Antenne und der Tag wird erkannt und löst das Relais aus.
Ich kann nicht steuern, wie oft der Tag erkannt wird, möchte das Relais bei einer Überfahrt aber nur einmal auslösen.

Ich hoffe das war verständlicher
Gruß
Thilo

agmue

Ich habe den Eindruck, Du möchtest eine Schrittkette (= finite state machine = endlicher Automat) programmieren.
Wahnsinn und Verstand trennt nur eine dünne Wand. (Daniel Düsentrieb)

Hoplost

Hallo,

Das müsste ich erst einmal googeln :).
Da bin ich unsicher.
Eigentlich möchte ich nur erreichen das bei erkennen der lok das Relais nur einmal ausgelöst wird. Der Arduino scheint sich aber irgendwie zu merken wie oft er den Rfid-Tag hintereinander erkannt hat. So oft läuft er dann schön sein Programm ab.

Evtl. Besteht ja die Möglichkeit den Arduino nach auslösen des Relais auszuschalten und gleich wieder ein.

Gruß Thilo

agmue

Das müsste ich erst einmal googeln :).
Im Forum könntest Du nach "agmue anleitung" suchen, da habe ich als Anfänger was für Anfänger geschrieben. Ich übernehme keine Garantie, daß es Dir hilft, aber einen Versuch wäre es wert und den Autor könntest Du fragen ;)

Bitte beachte auch die dort gesammelten Links zu anderen Erklärungen.
Wahnsinn und Verstand trennt nur eine dünne Wand. (Daniel Düsentrieb)

themanfrommoon

Moin,

du schriebst, dass LEDs nicht gehen, weil das sichbare Licht nervt.

Nimm ne IR Led.
Das Licht siehst du nicht und die Lösung ist super einfach.

Lieben Gruß,
Chris

MicroBahner

#22
Nov 17, 2019, 12:27 pm Last Edit: Nov 17, 2019, 12:28 pm by MicroBahner
Der Arduino scheint sich aber irgendwie zu merken wie oft er den Rfid-Tag hintereinander erkannt hat. So oft läuft er dann schön sein Programm ab.
Ja, im Prinzip ist das so. Die serielle Schnittstelle hat einen Puffer, und da liegen dann alle empfangenen Telegramme drin ( zumindest soviele, wie der Puffer fasst ). Durch deine delays können die aber nicht alle sofort gelesen werden. Nachdem das erste gelesen wurde, schaltest Du das Relais an, und dann macht der Arduino eine Minute lang nichts kann also den Empfangspuffer auch nicht leeren. Erst nach der Minute wird dann das nächste Telegramm aus dem Puffer gelesen und alles beginnt von vorn.

Fazit:
zum einen musst Du ohne delays programmieren, so dass der Puffer auch geleert werden kann, während das Relais angezogen ist.
Zum anderen darfst Du während das Relais angezogen ist, nicht auf weitere Telegramme reagieren.
Gruß, Franz-Peter

postmaster-ino

Hi

Besonders der 2.te (also letzte) Hinweis ist der Knackpunkt.
RFID-Erkennen (IMMER)
Du erkennst keinen RFID-Tag ... dann machen wir auch Nichts!
Wir sind NICHT in der Wartezeit oder der Nachlaufzeit und Du erkennst einen der RFID-Tags Lok1, Bill oder Bob - Du merkst Dir die Zeit, daß Du das Relais AN hast und schaltest das Unterbrechungs-Relais an.
Das Relais ist AN und die Wartezeit um? Nein -> wir machen (wieder) Nichts (auch kein delay()!!!)
Das Relais ist AN und die Wartezeit um? Ja -> Du merkst Dir die zeit, daß wir in der Nachlaufzeit sind und schaltest das Relais wieder ab.
// hier wird der RFID-Tag wohl immer noch erkannt, die Lok steht ja noch auf dem Sender ...)
Wir sind in der Nachlaufzeit und die Wartezeit ist um? Nein -> Du ahnst Es ... Nichts wird gemacht
Wir sind in der Nachlaufzeit und die Wartezeit ist um? Ja -> Wir vergessen, daß wir in der Nachlaufzeit sind - ab jetzt werden wieder RFIDs ausgewertet.

Ungefähr so sollte Das klappen.

MfG
anscheinend ist Es nicht erwünscht, einen Foren-internen Link als 'Homepage' einzubinden, damit JEDER nur einen Klick von combie's Liste zum Thema State-Maschine entfernt ist.
... dann eben nicht ...

MicroBahner

#24
Nov 17, 2019, 03:46 pm Last Edit: Nov 17, 2019, 03:49 pm by MicroBahner
Hallo Thilo,
ich hab das mal in einen kleinen Sketch gegossen  ;) . Für den Anschluß des Rfid-Lesers habe ich SoftwareSerial verwendet, dann sind die Schnittstellen für den Leser und die für den seriellen Monitor sauber getrennt.
Für das einfache hantieren mit Zeitverzögerungen ( der EggTimer ) musst Du die MobaTools installieren. Das geht einfach über den Bibliotheksmanager ( im Suchfeld 'mobatools' eingeben ).

Code: [Select]




#include <MobaTools.h>
#include <SoftwareSerial.h>
// start text character
#define STX 2
// end text character
#define ETX 3
const byte rxPin = 8;       // hier wird der Rfid-Leser angeschlossen
const byte txPin = 9;
SoftwareSerial rfidSerial = SoftwareSerial( rxPin, txPin );

EggTimer delayTimer; // für Zeitverzögerungen

int relaisPin = 5;

// buffer to hold the last code read from Serial
char rfidValue[13];

boolean readRFID(char (&rfidBuf)[13])
{   // die Zeichen vom Rfid-Leser werden gelesen. Die Funktion muss im loop() ständig
    // aufgerufen werden, und schaut dann nach, ob Zeichen angekommen sind.
    // Sobald ein komplettes Telegramm empfangen wurde, ist der Funktionswert 'true', und
    // das Telegramm wird in den übergebenen Puffer kopiert.
    static byte rfidIx = 0; // Index im Empfangspuffer
    static char buf[13];    // interner Empfangspuffer
    char c;
    boolean fertig = false;
    while (rfidSerial.available()) { // Zeichen aus Puffer lesen
        c=rfidSerial.read();
        if ( c == STX ) {
            // Start einer Übertragung
            rfidIx = 0;
        } else if ( c == ETX ) {
            // Übertragungsende
            if ( rfidIx == 12 ) {
                // komplettes Telegramm empfangen
                buf[12]=0;
                strcpy( rfidBuf,buf);
                fertig = true;
            }
        } else {
            // Zeichen in Puffer eintragen
            if ( rfidIx < 12 ) {
                buf[rfidIx++] = c;
            }
        }
    }
    return fertig;
}


void setup()
{
  Serial.begin(9600);
  rfidSerial.begin(9600);
  while(!Serial);
  Serial.println("waiting for RFID...");
}

enum state_t {WARTEN,VORLAUF,RELAIS};   // Die möglichen Zustände der Schrittkette
state_t zustand = WARTEN;               // aktueller Zustand der Schrittkette

void loop()
{
    boolean gotRfid;
    gotRfid = readRFID(rfidValue); // Empfang vom Rfid-Leser ( bei jedem loop-Durchlauf aufrufen! )
   
    switch ( zustand ) {
      case WARTEN: //------ warten bis Rfid Tag erkannt ------------
        if (gotRfid) {
             if (strcmp(rfidValue,"0462D7E57723")==0) {
                Serial.println("lok 1");
                delayTimer.setTime(3000);      //Hier eine zusätzliche Wartezeit bis das Relais auslöst
                zustand = VORLAUF;      // zum nächsten Schritt weiterschalten
                }
            else if (strcmp(rfidValue,"123456789012")==0)
              Serial.println("Hello Bill!");
            else if (strcmp(rfidValue,"800C4C028042")==0)
              Serial.println("Hello Bob!");
            else
            {
              Serial.print("Fuck off! ");
              Serial.println(rfidValue);
            }
        }
        break;
      case VORLAUF: // warten bis Vorlaufzeit abgelaufen
        if ( !delayTimer.running() ) {
            digitalWrite(relaisPin, HIGH);
            Serial.println("Relais EIN");
            delayTimer.setTime(60000); // Relais 1 Minute einschalten
            zustand = RELAIS;      // zum nächsten Schritt weiterschalten
        }
        break;
      case RELAIS: // wenn Timer abgelaufen, Relais abschalten udn wieder von vorn
        if( !delayTimer.running() ) {
            digitalWrite(relaisPin, LOW);
            Serial.println("Relais AUS");
            zustand = WARTEN;
        }
    } // Ende der Schrittkette
}



Wie Du siehst, enthält der Code kein einziges delay mehr.
Gruß, Franz-Peter

postmaster-ino

Hi

@microbahner - warum kein const byte bei der Pin-Definition? Schadet nicht, frisst kein Brot und der geneigte Anfänger lernt, wie's sein sollte.

Sonst eine saubere Umsetzung.
Anmerkung: Für mehrere parallele Verzögerungen braucht's hier dann mehrere EggTimer.
Hier sind die Verzögerungen hintereinander, also kommt man hier mit Einem aus.
Wenn man aber parallel dazu eine weitere State-Maschine laufen lassen will (was problemlos mit diesem Rezept möglich ist), dürfen sich diese beiden Verzögerungen nicht gegenseitig stören.

MfG
anscheinend ist Es nicht erwünscht, einen Foren-internen Link als 'Homepage' einzubinden, damit JEDER nur einen Klick von combie's Liste zum Thema State-Maschine entfernt ist.
... dann eben nicht ...

MicroBahner

warum kein const byte bei der Pin-Definition?
Bei von mir neu eingefügten Zeilen ist das ja so. Ok, bei den unveränderten Zeilen habe ich es nicht korrigiert - sonst erkennt Thilo seinen Sketch ja garnicht mehr wieder  ;) . Aber das kann er dann ja selbst machen.

Für mehrere parallele Verzögerungen braucht's hier dann mehrere EggTimer.
Ja, wenn er den Sketch weiter aufbohren möchte ist das so. Aber solange der Speicher reicht  ;) kann er sich beliebig viele anlegen - braucht 5 Byte Ram/Instanz.
Gruß, Franz-Peter

Hoplost

Hallo,

Ich bin beeindruckt. Meine Probleme werden schneller gelöst als ich sie vollumfänglich erkennen kann.

Das ist alles sehr interessant. Ich benötige wohl einen Augenblick das zu verstehen und umzusetzen.

Dankeschön!
Thilo

Frank501

Auch wenn der TO sich scheinbar bereits auf RFID eingeschossen hat möchte ich hier noch eine andere Alternative einwerfen.

Statt einem Magneten, der einen Hallsensor oder einen Reed-switch schaltet, könnte man auch einfach eine LED mit 36KHz pulsen und in die Lok oder den Wagen einbauen.

Als Empfänger kann man dann einen TSOP1736, wie er für Infrarotfernbedienungen genutzt wird, in die Schiene bauen.

Jedes Mal, wenn die LED (also der Wagen oder die Lok in der diese eingebaut ist) über den Empfänger fährt, gibt dieser dann einen Impuls aus.

Dadurch kann man zwar nur einen Zug erkennen, aber so wie ich den Eröffnungspost lese, reicht das dem TO.

themanfrommoon

#29
Nov 18, 2019, 06:06 am Last Edit: Nov 18, 2019, 06:08 am by themanfrommoon
Moin,

Die Carrera Bahnen machen das mit unterschiedlichen Frequenzen je Auto. So kann man also auch per IR unterschiedliche Züge erkennen.

(Mein Post #21 wurde aber auch vollstädig ignoriert. So ist das wohl heutzutage)

Go Up