| |
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 PollThread 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 PollThread. 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 setzen die Klassen Thread und AutoResetEvent
der .NET Framework Klassenbibliothek des Namespace System.Threading (using
System.Threading;) ein. Übersichten und Details dazu siehe Hilfe
System.Threading-Namespace und Thread-Member sowie WaitHandle-Member,
AutoResetEvent-Member. Die .NET Framwork Klassen sind von Haus aus threadfest.
Literatur Andreas Kühnel Das Thread Kapitel
ist instruktiv, es fehlt aber ein AutoResetEvent Beispiel.
Details
Thread Klasse zum Erstellen und Betreiben eines Threads :
Dim robThread As New Thread(AddressOf robExecute)
Erstellen eines neuen Threads und der Nutzroutine als Callback Routine
(Delegate). Die Nutzroutine ist also Bestandteil (eine Methode) der umgebenden
Klasse. Der Thread wird erst durch robThread.Start();
gestartet und durch Erreichen des Endes der Routine beendet.
AutoResetEvent Klasse zum Erstellen und Betreiben eines
Synchronisations Mechanismus (Basis Waithandle), Alternative ManualResetEvent.
AutoResetEvent wird nach Abfrage zurückgesetzt ManualResetEvent nicht :
Dim robReady As New AutoResetEvent(False)
Event ist nicht signaled (false)
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)) :
frmMain
|
Der Hauptthread mit Form und Gesamtsteuerung |
ftR |
Instanz der Klasse FishFace zur Rob-Steuerung |
ftS |
Instanz der Klasse FishFace 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 |
frmMain global
- Anlegen der ftR und ftS Instanzen :
Dim ftR As New FishFace(False, False, 0)
Dim ftS As New FishFace(False, False, 0)
ohne AnalogScan, ohne Slave, mit default PollIntervall
- Thread Member
Dim robThread As Thread
Dim stanzeThread As Thread
Instanziert werden kann hier noch nicht, da die Callback Routine
nicht statisch ist.
- Events
Dim robReady As AutoResetEvent
Dim stanzeReady As AutoResetEvent
cmdAction_Click
- Herstellen der Verbindung zu den Interfaces :
ftR.OpenInterface("COM2", False)
ftS.OpenInterface("COM1", False)
ohne Unterbrechung durch Application.DoEvents();
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 und Events für Rob/Stanze
robThread = New Thread(AddressOf robExecute)
stanzThread = New Thread(AddressOf stanzThread)
ohne sie zu starten
- Starten der Threads
robThread.Start()
stanzThread.Start()
robExecute
Die Nutz-(CallBack/Delegate)Routine 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). WaitForMotors wartet auf das Erreichen
aller vier Endpositionen eine unbegrenzte Zeit (0).
- BetriebsSchleife
Do Loop While Not ftR.Finish()
wird durchlaufen bis der Thread von außen einen EndeWunsch empfängt
(siehe auch cmdEnde_Click).
- In der Betriebsschleife
frmThreadMain.lblStatus.Text = "...."
Anzeige des aktuellen Status
ftR.SetMotor(...
ftR.SetMotor(...
ft.WaitForMotors(0, ...)
Ausführen der Teilschritte Greifen des Teils, Weg zur Ablage auf
dem Transportband,
- Weiter mit Warten auf stanzeReady
stanzeReady.WaitOne()
Ablegen auf dem Transportband nach dem Signal
Nach dem Ablegen : Setzen Signal RobReady
robReady.Set()
und ohne Halt zurück zum Magazin.
- Und nach Erhalt des Ende-Wunsches
Fahren des Robots auf eine Ruheposition.
stanzExecute
Nutzroutine des Threads, ähnlich wie robThread.
- 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 Ende-Wunsches
Abstellen der Lampen.
cmdEnde_Click
Kunstvolles Beenden des Stanzbetriebes :
- Ende-Wunsch an Robot
ftR.NotHalt = true
stanzeReady-Set()
robThread.Join()
NotHalt wird beim Schleifenende durch Finish ausgewertet, die
Schleife und damit der Thread werden beendet. Vorher muß es aber erst
soweit kommen : normales signalisieren StanzeReady. Anschließend Warten auf
das Thread-Ende.
- Ende-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.
|