Leseprobe
Inhaltsverzeichnis
Einleitung
1. Spezifikation Hochregallager v1.2 (Stand 04.05.02)
2. Eigenschaften und Aufgaben der Objekte
2.1. Palette.java
2.2. Regal.java
2.3. Lager.java
2.4. Einheit.java
2.5. LagerCanvas.java
2.6. Simulation.java:
2.7. Zusammenhang der Klassen im Flussdiagramm
3. Eigenschaften des Lagers
3.1. Eingänge:
3.2. Ausgänge:
3.3. Sortierpfad:
3.4. Auslagerungspfad:
4. Hochregallageranimation
5. Deadlock
Einleitung
Es soll Aufbau und Funktion eines Hochregallagers vereinfacht simuliert werden. Zur Lösung dieser Aufgabe wird die Programmiersprache Java genutzt. Die Fähigkeiten und Charakteristika von JAVA sollen genutzt werden, um die Programmieraufgabe zu lösen. Objektorientierte Programmierung steht dabei im Vordergrund.. Zusätzlich soll die Aufgabe visualisiert werden. Dazu wird sich dem GUI (Graphical User Interface - Grafische Benutzeroberfläche), genauer dem JAVA-Paket AWT (Abstract Windowing Toolkit) bedient. Mit dem Start des Programms wird ein Fenster geöffnet, das die Fähigkeit des AWT nutzt. Das Hochregallager wird dargestellt, ebenso der Fahrweg der Paletten durch das Lager. Zur Vereinfachung wird davon ausgegangen, dass nur die Erdgeschossebene des Hochregallagers simuliert wird. In der Draufsicht, die auch in der Visualisierung benutzt wird, sind alle Wege und auch Palettenablageplätze gut sichtbar
1. Spezifikation Hochregallager v1.2 (Stand 04.05.02)
Anzahl der Eingänge: 1 x (Palettenanlieferung)
Anzahl der Ausgänge: 2 x (Palettenabfuhr durch LKW)
Maximale Anzahl der Palettenplätze: 120
Maximale Anzahl der unterschiedlichen Paletten: 120
Zwei verschiedene LKW-Größen:
- LKW 7,5t: max. 4 Paletten
- LKW 25t: max. 10 Paletten (4 auf LKW, 6 auf Anhänger)
Ausgangsvoraussetzung:
- Die LKW können unterschiedliche Palettensorten laden.
- Einige LKW werden nur teilweise beladen und fahren dann ab.
- Bei genügend Platz werden die Paletten sortenorientiert gelagert. Steuerfeld in der Grafik stellt Bedienfeld zur Verfügung NOTAUS vorsehen
- Gemischte Lager werden bei „Leerlauf“ umsortiert um sortenorientiert gelagert zu werden.
- Die älteste Palette einer Sorte soll als erste ausgeliefert werden. (Verderblichkeit)
Die im Lager befindlichen Palettensorten sollen gezählt werden.
Vereinfachend haben alle Paletten die gleiche Grundfläche
Annahmen:
- Die Förderbänder bestehen aus Rollen, die sich einzeln ein- und ausschalten lassen.
- 5 Hauptförderbänder, 2 Fahrstühle (am Ausgang der Lagerförderbänder), 12 Lagerförderbänder.
- Die Förderbänder können nur in eine Richtung laufen. Sie können sich überschneiden.
- Die Eigenschaften eines jeden Platzes im Lager sind durch eine Tabelle bestimmt (Array).
- Jede Palette, die ein neues Ziel erhält, wird als „Thread“ behandelt, bis sie ihr Ziel erreicht hat.
- Bei Kreuzungspunkten wird eine eindeutige Vorfahrtsregelung festgelegt.
Ausnahmen:
- Zu viele Paletten
- Sortiervorgang läuft - Ausgabe steht an
- Sortiervorgang läuft - Eingabe steht an
2. Eigenschaften und Aufgaben der Objekte
2.1. Palette.java
Die Palette wird mit einer Ware initialisiert. Sie erhält eine leere Auftragsliste. Diese enthält das nächste Ziel der Palette. Es muss immer die unmittelbar anschließende Einheit sein, da die Palette die Topologie des Lagers schließlich nicht kennt.
Dann startet der Thread und schaut sich die Auftragsliste an. Wenn es einen Auftrag gibt, dann erkundigt sie sich beim Lager, wo an der aktuellen Einheit die gewünschte Einheit beginnt und wo die aktuelle Einheit verlassen werden muss.
Da das ganze Lager auf dem Schachbrett entworfen wurde, wird mit einfachen Indexen gearbeitet.
Die Palette fährt nun Schritt für Schritt dynamisch zum Ausgangspunkt und einen Schritt weiter in die neue Einheit.
Man muss sich eine Einheit so vorstellen, als wenn dort Plätze wären, in denen Paletten stehen können. Eingangspunkte und Ausgangspunkte sind die Stellen, an denen eine Palette eine Einheit verlässt (Ausgangspunkt) und eine neue Einheit betritt (Eingangspunkt). Beide Punkte müssen somit vorher schon mal definiert worden sein und genau das wird im Konstruktor von Lager gemacht.
Angenommen, das mittlere Band ist 5 "Plätze" lang und eine Palette steht auf dem ersten Platz, dann muss es einen Platz nach dem anderen abfahren bis es an seinem Ausgangspunkt ist (beispielsweise das vorletzte linke Regal, wäre Platz 4 auf dem Band) und dann in das Regal (also die neue Einheit wechseln).
Die Palette fährt dann: Band/Platz1 -> Band/Platz2 -> Band/Platz3 -> Band/Platz4 -> Regal/Platz1.
In LagerCanvas.java ist oben im Kommentar das Lager als Schachbrett aufgemalt, damit kann man es leicht nachverfolgen.
Danach wiederholt es sich ("gibt es einen Auftrag?"). Wenn es keinen gibt, legt die Palette sich mit wait() schlafen.
2.2. Regal.java
Der Sonderfall Regal wird separat behandelt, indem die Paletten an dessen Ende durchfahren müssen. Im Normalfall bleiben die Paletten am Anfang stehen. Dieses hat logische Gründe: Stünde ich am Ende und wechselte mit einem Schritt in die neue Einheit, dann wüsste ich nicht, wo das Ende der Palette in der neuen Einheit ist, da in den meisten Fällen kein Auftrag dafür existiert.
Teilt das Lager der Palette ein neues Ziel mit, dann trägt sie bei der Palette einen neuen Auftrag ein und weckt den Thread durch ein notify().
Ganz zu Beginn des Threadbeginns hat die Palette schließlich keine zugeordnete Einheit. Sie nimmt daher die Einheit aus dem ersten Auftrag und setzt sich an dessen Anfang. In diesem Fall das Einsortier-Band.
Abbildung in dieser Leseprobe nicht enthalten
2.3. Lager.java
Das Lager baut die logische Struktur des Lagers auf. Im Konstruktor werden alle Einheiten, also die Regale, die 5 Bänder, die LKW-Abfertigung und die Fahrstühle (wenn existieren) angelegt. Anschließend werden die Einheiten verknüpft: Wer ist wo wessen Ein- oder Ausgang. Dies benötigt eine Palette, damit sie weiß, wo sie hinausfahren und hineinfahren muss. Zudem gibt es kleine Funktionen zur Verwaltung der Paletten und sonstige kleine Abfragen des Lagers.
Das Lager ist insofern dynamisch, als dass es jede Größe annehmen kann! Die Aufgabenstellung hieß zwar 6x2 Regale á 10 Plätze, aber man kann Testweise auch mit 10x2 á 8 Plätzen arbeiten. Das muss in Simulation.java im init() lediglich geändert werden.
Das Lager selber führt das Neueinstellen einer Palette durch. Es versucht es solange, bis die Palette auf dem Sortierband eingestellt werden kann. Danach sucht das Lager für die Palette das Zielregal (mit getRegal()). Dieses neue Regal erhält die Palette als Auftrag. Somit beginnt die Palette von selbst (siehe oben, bei Palette) sich den Weg ans Ziel zu bahnen. Sollte die Suche nach einem Regal keinen Erfolg gehabt haben, weil alle voll sind, dann beendet sich das Programm. Die Regalsuche selber sucht erst in einem Regal der Palettenware, dann in einem leeren Regal, wenn kein leeres da ist, in einem Zwischenlager- Regal. Schließlich bietet das Lager Funktionen zur Bestimmung des Standortes innerhalb des Lagers, sei es für Regale, Bänder, ... , Paletten. Dies ist nötig, um korrekt animieren zu können.
Dem Lager fehlt noch die Logik, wie Paletten umgelagert (also aus den Zwischenlagern heraus in die Hauptregale), Paletten ausgeliefert etc werden.
2.4. Einheit.java
Dies ist die Basisklasse aller Einheiten (außer der Palette). Sie verwaltet Plätze, Richtung, Reservierungen und Speed der Einheit. Zudem bietet sie Funktionen zum Speichern der Ein- und Ausgänge jeder Einheit und zwar in Form eines eigenen Einheit IO-Objekts (siehe Ende des Sources). Für das Weiterbewegen einer Palette in der Richtung der Einheit gibt es die Funktionen reserviereNaechsten() und verschiebePalette(). Die Plätze einer Einheit dienen der Aufnahme der Palette und der Reservierung.
Von dieser Klasse werden Regal, Band, etc abgeleitet, da sie alle im Prinzip die selben Eigenschaften haben. Regal hat zusätzlich noch die Eigenschaft einer zugeordneten Sorte, die das Regal aufnehmen kann. Die noch fehlende Klasse Fahrstuhl hat eine Besonderheit: In ihr kann immer nur eine einzige Palette zur gleichen Zeit sein.
2.5. LagerCanvas.java
Dieses grafische Objekt kümmert sich komplett um die visuelle Erzeugung. Darin werden die statischen Elemente (auch ruhende Paletten) gezeichnet. Die dynamischen Paletten zeichnen sich selbst. Diese Diskrepanz müsste vollständig abgeschafft werden und die Aufgabe sollte LagerCanvas.java voll übernehmen, denn dann sieht die Animation auch gut aus. calcScale() berechnet einen Skalierungsfaktor, so dass das gesamte Lager auch voll ins Canvas hineinpasst. So kann während der Simulation die Fenstergröße geändert werden, und das Canvas passt sich automatisch an. Ich habe absichtlich eine ganzzahlige Skalierung verwendet, da die natürliche Skalierung unschöne Effekte beim Darstellen erzeugt. Die paint() Methode ruft für alle beteiligten Einheiten die Funktion zeichne() auf. Damit alle Einheiten diese Methode auch sicher implementiert haben, wurde die Schnittstelle Grafisch.java erzeugt, die jede grafische Einheit (also z.B. Regal und Grafisch bilden RegalGrafisch).
Abbildung in dieser Leseprobe nicht enthalten
2.6. Simulation.java:
Sie richtet das Fenster ein, baut das Lager zusammen, weist das Lager dem Canvas zu, richtet die Steuerungen im Fenster samt deren Aktions-Listener ein und wartet brav auf Knopfdruck. Auf Knopfdruck wird die bereits bekannte Palette ans Lager weitergegeben, eine neue Palette erzeugt, die Oberfläche aktualisiert und wieder gewartet. Um das Deadlock zu umgehen, das entsteht wenn man zu schnell den Button zum Anfordern neuer Paletten drückt, habe ich eine Schleife eingebaut und das "klick den Button" auskommentiert.
Diese Schleife wird maximal 120 mal aufgerufen. Mehr Paletten würden im idealen Fall nicht in das Lager passen. Die Konstante MAX_PALETTEN wird bei getNeueZufaelligePalette() geprüft. Wird der Wert überschritten, erzeugt die Funktion keine neue Palette mehr, da das Lager dann, da noch nicht ausgeliefert werden kann, voll wäre.
Die Paletten kommen nun im Abstand von 2000 bis 4000 ms (zufällig). Dieses wird überflüssig, sobald die Ampel korrekt geht. Sie geht in der momentanen Fassung nicht, da das Meldesystem an die Simulation fehlt.
Abbildung in dieser Leseprobe nicht enthalten
2.7. Zusammenhang der Klassen im Flussdiagramm
Abbildung in dieser Leseprobe nicht enthalten
Detaillierter macht es keinen Sinn, da das dann quasi dem Vorlesen des Quellcodes entspräche.
3. Eigenschaften des Lagers
3.1. Eingänge
Zur Anlieferung von Paletten gibt es einen Eingang, durch den immer eine Palette gleichzeitig in das Lager gelangen kann. Es kann gleichzeitig nur ein LKW erscheinen und Paletten anliefern. Die Reihenfolge der Palettensorten ist nicht festgelegt, sondern geschieht zufällig. Befindet sich im „ Eingangsbereich “ gerade eine Palette, so kann keine zweite Palette angeliefert werden. Nachfolgende Paletten müssen auf eine Freigabe für diesen Bereich warten.
Für den Eingangsbereich gibt es eine Vorfahrtsregelung, da aus drei verschiedenen Richtungen Paletten in diesen Kreuzungspunkt gelangen können. Aus den Richtungen „ links “ und „ rechts “ können Paletten aus Umsortiervorgängen kommen. Diese Paletten haben vorher schon mindestens einmal den Kreuzungspunkt durchfahren. Paletten, die von „ unten “ kommen werden gerade durch einen LKW angeliefert und befahren diese Kreuzung zum ersten Mal. Aus dem „ Eingangsbereich “ fahren die Paletten immer nur nach oben heraus, haben also nur eine mögliche Richtung zum Verlassen dieses Bereiches.
Um einen Zusammenstoß von mehreren Paletten auf der Kreuzung des Eingangsbereiches zu verhindern, muss eine eindeutige Vorfahrtsregelung getroffen werden. Sollte sich eine Palette gerade im Kreuzungsbereich befinden, so ist das Hineinfahren in den Kreuzungsbereich für weitere Paletten nicht gestattet. Sollte durch das Verlassen einer Palette der Kreuzungsbereich wieder frei werden, wird dieser Bereich wieder freigegeben. Da nun von drei Seiten (links, rechts, unten) gleichzeitig Palette einfahren könnten, müssen durch die Programmierung Prioritäten gesetzt werden. Von „ links „ und „ rechts “ kommen nur Paletten, die umsortiert bzw. umgelagert werden. Höchste Priorität haben die von „ unten “ kommenden Paletten. Es könnte sein, dass die gerade angelieferte Palette sofort wieder ausgeliefert werden muss, weil sich keine Palette des gleichen Typs im Lager befindet und ein LKW am Ausgang nur auf diesen Palettentyp wartet. Das Abfahren des LKW am Ausgang würde unnötig verzögert werden, wenn durch einen Umsortiervorgang Paletten von „ links „ und „ rechts “ angelieferte Paletten blockieren würden. Da die Paletten von „ links „ und „ rechts “ ungefähr die gleiche Priorität besitzen, wurde durch die Programmierung ein „ links „ vor „ rechts “ realisiert.
3.2. Ausgänge:
Zur Auslieferung von Paletten gibt es zwei Ausgänge, durch den jeweils immer eine Palette gleichzeitig aus dem Lager gelangen kann. An den beiden Ausgängen kann jeweils ein LKW erscheinen und Paletten anfordern. Zur Vereinfachung des Problems wird nicht berücksichtigt, in welcher Reihenfolge die Paletten auf die LKW geladen werden müssen. Befindet sich im „ Ausgangsbereich “ gerade eine Palette, so kann keine zweite Palette ausgeliefert werden. Nachfolgende Paletten müssen auf eine Freigabe für diesen Bereich warten. Für den Ausgangsbereich gibt es zusätzlich noch eine Vorfahrtsregelung, da aus drei verschiedenen Richtungen Paletten in diesen Kreuzungspunkt gelangen können. Aus den Richtungen „ links “ und „ rechts “ können Paletten aus dem Lager kommen. Paletten, die von „ unten “ kommen wurden gerade angeliefert und werden sofort wieder ausgeliefert, weil keine ältere Palette des gleichen Typs sich im Lager befindet. Aus der Kreuzung „ Ausgangsbereich “ fahren die Paletten immer nur nach oben heraus, haben also eine mögliche Richtung (aber zwei Ausgangsmöglichkeiten!) zum Verlassen dieses Bereiches.
Um einen Zusammenstoß von mehreren Paletten auf der Kreuzung des Ausgangsbereiches zu verhindern, muss eine eindeutige Vorfahrtsregelung getroffen werden. Sollte sich eine Palette gerade im Kreuzungsbereich befinden, so ist das Hineinfahren in den Kreuzungsbereich für weitere Paletten nicht gestattet. Sollte durch das Verlassen einer Palette (durch einen der beiden Ausgänge) der Kreuzungsbereich wieder frei werden, wird dieser Bereich wieder freigegeben. Da nun von drei Seiten (links, rechts, unten) gleichzeitig Palette einfahren könnten, müssen durch die Programmierung Prioritäten gesetzt werden. Von „ links „ und „ rechts “ kommen nur Paletten, die schon mindestens einmal eingelagert wurden und somit meistens älter sind als die von „ unten “ kommenden Paletten (wurden meistens gerade erst angeliefert). Da beide Ausgänge nach „ oben “ (und somit beide LKW) durch den gleichen Ausgangsbereich beliefert werden und wir das Prinzip der Verderblichkeit berücksichtigen, können von „ unten “ kommende Paletten länger warten. Die höhere Priorität erhalten die Paletten von „ links „ und „ rechts “, vorrangig vor den Paletten von „ unten “. Zusätzlich wurde durch die Programmierung ein „ links „ vor „ rechts “ realisiert, da die Paletten von „ links „ und „ rechts “ ungefähr die gleiche Priorität besitzen.
[...]