Über Threads

ftComputing : Programme für die fischertechnik-Interfaces und -konstruktionskästen
  
ftComputing.de
Home
Back
Sitemap
Index
Links
Impressum
Mail
 

Allgemeines

umFish30.DLL ist durch Trennung von Zugriff auf das Interface und den Zugriff der Anwendung auf die Interface Werte threadfähig. Das geschieht durch Auslagerung des Interfacezugriffs in einen eigenen Poll-Thread des Steuerung über den MultiMediaTimer erfolgt. Im Poll-Thread werden die Daten des Interfaces in regelmäßigen Intervallen abgefragt und gleichzeitig die Aufträge der Anwendung übermittelt. Die Kommunikation mit der Anwendung erfolgt über einen Kontrollblock (den ftiDCB), der von der Anwendung asynchron ausgelesen bzw. besetzt wird.

So ist es möglich auf ein Interface ( ggf. mit angeschlossenem Slave (Extension Module) unabhängig aus verschiedenen Threads zuzugreifen. Der eigentliche Zugriff auf die nur einmal vorhandene Resource Interface erfolgt immer über den ebenfalls nur einmal vorhandenen Poll-Thread. Der Zugriff auf einzelne Ein- bzw. Ausgänge ist ohne weitere Maßnahmen möglich. Beim gleichzeitigen Zugriff auf alle M-Ausgänge ist eine Maskierung der vom eigenen Thread nicht genutzten M-Ausgänge im MotorStatus-Wort erforderlich, da umFish30.DLL keine Verwaltung von TeilResourcen bietet. Maskierung meint hier Erhalt des Status der "fremden" M-Ausgänge.

Die nachfolgenden Beispiele beziehen sich auf C++Builder-Programme mit Thread-Klassen die von der (VCL)Klasse TThread abgeleitet wurden. Ein direktes Arbeiten mit den Win-API-Funktionen ist in gleicher Weise möglich, es bietet noch mehr Möglichkeiten (siehe auch Robot-Plant).

Programm RobStanze

Die Programme AmpelThread und RobStanze haben die gleiche Struktur. AmpelThread ist im Test wesentlich nervenschonender (es verhakt da nichts) und sollte der Ausgangspunkt eigener Bemühungen sein. RobStanze ist das attraktivere Modell, deswegen wird es hier besprochen. Bei den vorliegenden Programmen wird bei AmpelThread mit einem Intelligent Interface plus Extension Module an COM1 gearbeitet, bei RobStanze sind es Intelligent Interfaces an COM1 und COM2 (weil die Modelle so aufgebaut waren und weil die Verkabelung so einfacher ist (das Verbindungskabel des Extensionmodules ist zu kurz)) :

 frmThreadMain

Der Hauptthread mit Form und Gesamtsteuerung
ftR Instanz der Klasse TFishFace zur Rob-Steuerung
ftS Instanz der Klasse TFishFace zur Stanz-Steuerung
umFish30.DLL im Hintergrund : mit dem Poll-Thread
RobReady Event : Roboter hat Teil plaziert
Standard Security, autoReset, not signaled
StanzeReady Event : Stanze kann neues Teil verarbeiten
Standard Security, autoReset, not signaled
RobThread Thread mit der Robotersteuerung
StanzThread Thread mit dem Stanzprogramm

TfrmThreadMain::cmdActionClick

  • Anlegen der ftR und ftS Instanzen :
    ftR = new TFishFace(false, false, 0);
    ftS = new TFishFace(false, false, 0);
    ohne AnalogScan, ohne Slave, mit default PollIntervall
  • Herstellen der Verbindung zu den Interfaces :
    ftR->OpenInterface("COM2"), false);
    ftS->OPenInterface("COM1", false);
    ohne Unterbrechung durch Application.ProcessMessages();
    in einer try - catch Klammer um Openfehler abzufangen. Weitere try/catch wären sinnvoll, aber man hört es auch so laut genug.
  • Anlegen der Threads für Rob/Stanze
    RobThread = new TRobThread(true);
    StanzThread = new TStanzThread(true);
    ohne sie zu starten
  • Zuordnen der EndeRoutinen
    RobThread->OnTerminate = RobEnde;
    StanzThread->OnTerminate = StanzEnde;
  • Starten der Threads
    RobThread->Suspended = false;
    StanzThread->Suspended = false;

TRobThread::Execute   

Die Nutzroutine des Threads.

  • Anfahren der Home Position
    ftR->SetMotor(mSaule, ftiLinks, 15, 999);
    ftR->SetMotor(mArmV, ftiLinks, 15, 999);
    ftR->SetMotor(mArmH, ftiLinks, 15, 999);
    ftR->SetMotor(mGreifer, ftiLinks, 15, 999);
    ftR->WaitForMotors(0, mSaule, mArmV, mArmH, mGreifer);
    Alle vier Motoren des Robot werden simultan mit voller Geschwindigkeit gestartet (15), sie sollen 999 Impulse oder bis zum Erreichen des zugehörenden Endtasters laufen (ca. 360 Impulse sind eine volle Drehung, also bis zu den Endtastern). WaitFor wartet auf das Erreichen aller vier Endpositionen eine unbegrenzte Zeit (0).
  • BetriebsSchleife
    do {} while(!Terminated)
    wird durchlaufen bis der Thread von außen einen EndeWunsch empfängt (siehe auch cmdEndClick).
  • In der Betriebsschleife
    frmThreadMain->lblStatus->Caption = "...."
    Anzeige des aktuellen Status
    ftR->SetMotor(...
    ftR->SetMotor(...
    ft->WaitForMotors(0, ...);
    Ausführen der Teilsschritte Greifen des Teils, Weg zur Ablage auf dem Transportband,
  • Weiter mit Warten auf StanzeReady
    while(!StanzeReady-WaitFor(100) == wrSignaled);
    Ablegen auf dem Transportband nach dem Signal
    Nach dem Ablegen : Setzen Signal RobReady
    RobReady->SetEvent();
    und ohne Halt zurück zum Magazin.
  • Und nach Erhalt des Terminate-Wunsches
    Fahren des Robots auf eine Ruheposition.

TStanzThread::Execute

Nutzroutine des Threads, ähnlich wie TRobThread.

  • Herstellen der Startposition
  • Betriebsschleife
  • In der Betriebsschleife
    Gleich zu Anfang Warten auf RobReady und anschließendes Signalisieren StanzeReady
  • Weiter in der Betriebsschleife
  • Und nach Erhalt des Terminate-Wunsches
    Abstellen der Lampen.

TfrmThreadMain::cmdEndeClick

Kunstvolles Beenden des Stanzbetriebes :

  • Terminate-Wunsch an Robot
    RobThread-Terminate();
    StanzeReady-SetEvent();
    RobThread-WaitFor();
    Der Ende-Wunsch wird zunächst nicht vom Thread erkannt, da er im Wait auf StanzeReady hängenbleibt, deswegen ein künstliches StanzeReady und dann warten, dass ers kapiert. d.h. der RobThread wird regulär zu Ende gefahren.
  • Terminate-Wunsch an Stanze
    analog Robot
    daran denken es wird noch ein Teil benötigt, wenn die Testbefehle
    ftS->WaitForLow(ePhotoV);
    ftS->Pause(1234);
    noch vorhanden sind.
  • Abschlußarbeiten.

Anmerkungen

Threadfestigkeit : umFish30.DLL ist es, s.o. Die VCL-Umgebung (die Windowsoberfläche) nicht immer, dann hilft Synchronize(.....); Oder ein Ausweichen auf eine threadfeste Alternative (z.B. TThreadListe ...). Weiteres siehe Handbuch/Hilfe Kapitel 7.

Globale Variable : frmThreadMain, ftR, ftS sind solche und damit recht praktisch und deswegen folgerichtig nichts für Puristen. frmThreadMain ist höhere Gewalt, aber ftR, ftS kann man auch dem Thread-Konstruktur als Parameter mitgeben (und dann gleich auch noch lblStatus.).