Der
Legoroboter mit dem Raspberry Pi
von
Andre Mönnich & Eric Ritter
Kapitel 1: Inhaltsverzeichnis | 2
Inhaltsverzeichnis
Seite
Vorworte 4
1 Unsere Hardware 5
1.1 Der Raspberry Pi 5
1.2 L298N Stepper Motor Driver Board 5
1.3 Die Legomotoren 6
1.4 Die SD-Karte 7
1.5 Der Akku 7
1.6 Der WLAN-Adapter 8
1.7 Die Webcam 8
1.8 Der Joystick 8
1.9 Der Ultraschallsensor 9
1.10 Das Steckboard 9
1.11 Jumperkabel und der 9V-Batterieclip 9
1.12 Hardwareübersicht 10
2 Erste Schritte 11
2.1 Das Betriebssystem 11
2.2 SSH-Verbindung 15
2.3 WinSCP 16
2.4 Remotedesktop 17
2.5 Einrichtung der WLAN-Verbindung 18
3 Die Entwicklungsumgebung 20
3.1 Installation von Eclipse 20
3.2 Jars einbinden 20
3.3 Windows Builder installieren 21
4 Motoransteuerung 23
Kapitel 1: Inhaltsverzeichnis | 3
4.1 Pi4J-Installation 23
4.2 Ein Java-Programm kompilieren 24
4.3 Ausführen eines Java-Programms 24
4.4 Anschluss der Motoren 25
4.5 Erstes Ansteuern 26
4.6 Steuerung per Konsole 28
4.7 Ansteuerung per Tastatur 30
5 Server und Client 33
5.1 Server und Client Beispiel 33
5.2 Server-Anpassungen 35
5.3 Der Client 38
6 Webcam 58
6.1 Webcamstream-Software installieren 58
6.2 Webcamstream starten 58
6.3 Webcampanel 59
6.4 Webcam in den Client einbinden 60
7 Joystick 66
8 Ultraschallsensor 73
8.1 Funktionsweise 73
8.2 Der Anschluss 74
8.3 Python-Programm 75
8.4 In den Client einbinden 76
9 Verbesserungen 82
9.1 Speichern der Einstellungen 82
Fazit 88
Anhang 89
Quellenverzeichnis 117
Kapitel 1: Vorworte | 4
Vorworte
Im Hardwareunterricht der Klasse 11 BG D der Adolf-Reichwein-Schule in Marburg
kam Herr Barg mit einer tollen Projektidee. Die Schüler sollten lernen, wie man mit
einem nicht so leistungsstarken Einplatinenrechner, gute Produkte herstellen konnte.
Was die Schüler mit ihren Einplatinenrechner Raspberry Pi anstellen wollten, durften
die Schüler selbst entscheiden.
Wir, Andre Mönnich und Eric Ritter, haben uns für einen selbstgebauten Legoroboter
entschieden. Wir haben uns für dieses Thema entschieden, da wir wussten, dass es
dabei kaum Vorlagen gab und dass man alles selber basten bzw. programmieren
muss. Dabei sind wir stark in die Materie eingestiegen und haben uns viel
Eigenwissen angeeignet. Dies hilft uns sehr viel in unserem Softwareunterricht
weiter.
Wir versuchen in der nachfolgenden Dokumentation unsere Vorgehensweise etwas
näher zu bringen.
Viel Spaß beim Lesen ;-)
Kapitel 1: Unsere Hardware | 5
Abbildung 1-2: L298N
Stepper Motor Driver
Kapitel 1
Unsere Hardware
In diesem Kapitel beschreiben wir unsere genutzte Hardware. Am Ende dieses Kapitels gibt
es auch nochmal eine Gesamtübersicht über die Hardware.
Der Raspberry Pi Der Raspberry Pi ist ein von der Britischen Firma Raspberry Pi Foundation entwickelter
Einplatinenrechner von der Größe einer Kreditkarte.
Im Verglich zu einem normalen PC ist dieser Rechner sehr einfach
aufgebaut und mit einem Preis von momentan ca. 34 €
(Amazon: 02.04.2014; 20:33) ist er äußerst günstig. Er
wurde mit dem Ziel entwickelt, auch jungen
Menschen den Erwerb von Programmier- und
Hardwarekenntnis zu ermöglichen. Bei diesem
Preis darf man natürlich keine Höchstleistungen
erwarten… Die Platine enthält ein Ein-Chip-System
von Broadcommit einem 700-MHz-ARM11-Prozessor
sowie 256 MB Arbeitsspeicher beim Modell A, das
Modell B hat 512 MB. Das Modell B hat außerdem unter
anderem eine Ethernet-Schnittstelle und einen zweiten USB-
Anschluss. Als Betriebssystem können angepasste Linux Distributionen, wie zum Beispiel
Raspbian, Android und so weiter, oder andere Betriebssysteme verwendet werden, welche
die ARM-Architektur unterstützen. Als Speichermedium dient eine einfache SD-Karte, die
auch als Bootmedium genutzt wird. Doch dazu mehr in Kapitel 2.
L298N Stepper Motor Driver Board Das L298N Stepper Motor Driver Board ist zum Steuern
von zwei Gleichstrom-Motoren gedacht. Die Platine ist mit
dem Chip L298N ausgestattet. Neben dem Chip besteht
dasBoard im Wesentlichen aus vier Pins, zweimal jeweils
zwei Anschlüsse für die Gleichstrom-Motoren, einen
Ground-anschluss sowie dem Plus- und dem Minus-Pol.
Außerdem besitzt die Platte noch zwei Transistoren, die auf
der Platte zu sehen sind.
Abbildung 1-1:
Raspberry Pi, Model B
Kapitel 1: Unsere Hardware | 6
Abbildung 1-4: Umdrehungen pro Minute abhängig von der Spannung
Wenn wir damit nun einen Motor steuern möchten, so legen wir ein wenig Spannung auf
einen der vier Pins. Mit diesem Strom schließt der Transistor den Stromkreis so, dass der
Strom durch den Motor fließt. Genauere Erklärungen und der Schaltplan finden sich im
Kapitel 4.
Die Legomotoren Als Motoren für unseren Legoroboter benutzen wir
zwei XL-Motoren der Power Functions Reihe von
Lego.
Bei diesen Motoren handelt es sich um
Gleichstrommotoren, die nur eine
Geschwindigkeitsstufe besitzen
Das Gewicht eines Motors beträgt 69g.
Betrieben werden die Motoren mit 9V.
Die Umdrehungszahl beträgt 220
Umdrehungen pro Minute. Der
Leerlaufstrom beträgt 80 mA.
Die Spannung verhält sich proportional
zur Umdrehungsgeschwindigkeit (wie es
bei Gleichstrommotoren üblich ist).
Daraus ergibt sich dasnebenstehende
Diagrammin Abbildung 1-4. Es ist auch
möglich, die Motoren auch mit mehr als
9 V Spannung zu betreiben. Allerdings
kann nicht garantiert werden, dass die
Motoren über einen längeren Zeitraum
keinen Schaden nehmen. Daher werden
wir die Motoren mit 9 V betreiben. Zur
Stromversorgung kommen wir später
noch.
Die maximale Drehkraft beträgt 40 N/cm².
Dabei beträgt die maximale
Stromaufnahme 1,8 A. Es ist zu beachten,
dass die Temperatur dabei schnell
ansteigt. Da die Motoren mit einem
Überlastungsschutz ausgestattet sind,
sollte ein Durchbrennen nicht möglich
sein, dies hat aber auch die Folge, dass
die maximale Leistung nur für einen
kleinen Moment verfügbar ist.
Abbildung 1-5: Umdrehungen pro Minute und Stromstärke abhängig vom Drehmoment
Abbildung 1-3: Der Legomotor
Kapitel 1: Unsere Hardware | 7
Abbildung 1-8: Power Rocket 4000
Die Abbildung 1-5 zeigt die Umdrehungen pro Minute und die Stromstärke abhängig vom
Drehmoment.
Die Abbildung 1-6zeigt zum Schluss noch die Leistung der Motoren.
Die Kraft der Motoren wird auf Legoketten übertragen, womit der Roboter später fahren wird.
Die SD-Karte Als Speicherkarte verwenden wir eine SDHC-Speicherkarte der Firma
Transcend mit 8 GB und der Geschwindigkeitsklasse 10. Eine weniger
leistungsstarke Speicherkarte würde auch funktionieren. Eine
Speicherkarte mit einer hohen Geschwindigkeit hat den Vorteil, dass der
Raspberry Pi schneller läuft, da der Raspberry Pi keinen eigenen
Speicher hat und deshalb alle Daten auf der Speicherkarte
gespeichert werden müssen.
Der Akku Damit der Roboter eine hohe Mobilität hat, soll die Stromversorgung über einen
Akku geschehen. Dazu verwenden wir den tragbaren 5V Akku „Power
Rocket 4000“, von Digitus.
Alle Geräte, deren Stromverbindung über USB funktioniert
können mit ihm geladen werden. Dazu muss lediglich das
mitgelieferte USB-Kabel mit dem Gerät und der mit „OUT
5V“ gekennzeichnete USB-Buchse des Akkus verbunden
werden und die Taste gedrückt werden. Wenn die
Verbindung nicht mehr besteht, schaltet sich der Akku
nach 30 Sekunden automatisch ab. Wenn das Gerät
überlastet wurde, löst eine Sicherheitsschaltung aus und der Akku geht in den geschützten
Modus. Um diesen zu beenden muss der Akku einfach aufgeladen werden.Es gibt drei
Kapazitätsanzeigen: 30%, 70% und 100%. Wenn die 30%-Anzeige leuchtet, ist die Kapazität
fast erschöpft. In diesem Fall sollte man den Akku wieder aufladen.Um den Akku wieder
Aufzuladen muss einfach ein USB-Ladekabel mit der „IN“-Buchse verbunden werden.
Während des Ladevorgans blinkt die Kapazitätsanzeige. Sobald der Akku aufgeladen ist,
Abbildung 1-6: Leistung des Motors
Abbildung 1-7: SD-Speicherkarte
Kapitel 1: Unsere Hardware | 8
Abbildung 1-11: Der Joystick
leuchtet die 100%-Anzeige.Die Speicherkapazität beträgt 4000 mAh und das Gewicht 68g.
Die Abmessungen betragen 86mm x 40mm x 27mm.
Die Motoren werden mit einem externen 9 V-Block betrieben, da die 5 V des Akkus nicht
ausreichen.
Der WLAN-Adapter Um den Raspberry Pi später kabellos steuern zu können, benötigen
wir einen WLAN-Adapter. Wir verwenden dazu den nano USB-
Adapter EW-7811Un von Edimax. Er verwendet den Standard
IEEE802.11b/g/n. Die Datenübertragungsrate beträgt bis zu 150Mb/s.
Mit USB 2.0 wird er mit dem Raspberry Pi verbunden.
Die Webcam Damit man später sehen kann, wo der Roboter hinfährt ohne,
dass man ihn im direkten Sichtfeld hat, statten wir den Roboter
mit einer Webcam aus. Wir verwenden dazu die C170
von Logitech. Sie hat eine Auflösung von 1024 x 768
Pixel. Verbunden wird sie mit dem Raspberry Pi per
USB.
Der Joystick Da wir später eine Steuerung per Joystick als Alternative
anbieten wollen, brauchen wir natürlich einen Joystick. Da es
aber nur eine Alternative ist, gibt es auch noch andere
Möglichkeiten zur Steuerung und ein Joystick ist nicht zwingend
notwendig.
Wir verwenden den Extreme™ 3D Pro von Logitech. Er verfügt über
3 Achsen, einen Schieberegler, 12 Tasten und einen
Rundumblickschalter.
Für unser Programm ist es jedoch nicht notwendig, dass ein
Joystick verwendet wird, der über einen solchen
Funktionsumfang verfügt. Unser Programm benötigt lediglich die
drei Achsen. Sollten nur zwei Achsen verfügbar sein ist die Steuerung
auch möglich, jedoch ist das Drehen auf der Stelle dann nicht
per Joystick möglich.
Abbildung 1-9: Der WLAN-Stick
Abbildung 1-10: Die Webcam
Kapitel 1: Unsere Hardware | 9
Abbildung 1-12: Der Ultraschallsensor
Abbildung 1-13: Das Steckboard
Abbildung 1-14: Jumperkabel Abbildung 1-15: 9V-Batterieclip
Der Ultraschallsensor Als eine kleine Erweiterung haben wir uns noch
einen kleinen Ultraschallsensor aus China bestellt.
Damit wollen wir den Freiraum vor dem Roboter
messen. Wir besitzen das Modell HC-SRO4. Dieser
arbeitet mit einer Spannung von 5 V. Dabei muss
darauf geachtet werden, dass 5 V die GPIO-Pins
beschädigen könnte. Daher müssen wir hier mit
Widerständen arbeiten. Der Sensor kann eine
Entfernung von 2 – 500 cm messen und arbeitet
dabei auf einer Frequenz von 40 kHz, was Menschen
nicht mehr hören können. Weitere Informationen finden sich in Kapitel 8.
Das Steckboard Für den Ultraschallsensor benötigen wir eine kleine Schaltung.
Um diese übersichtlich und kompakt an den Roboter
anzubringen, haben wir uns für ein kleines Steckboard
mit 400 Kontakten entschieden. Dies haben wir über
Amazon aus China bestellt.
Jumperkabel und der 9V-Batterieclip Nun benötigen wir noch Jumperkabel, um die einzelnen Komponenten miteinander zu
verbinden und den Schaltkreis auf dem Steckboard aufzubauen. Für die Stromversorgung
der Motoren wird außerdem ein 9 V-Batterieclip gebraucht.
Kapitel 1: Unsere Hardware | 10
Abbildung 1-16: Hardware-übersicht
Hardwareübersicht
Kapitel2: Erste Schritte | 11
Kapitel2
Erste Schritte
In diesem Kapitel richten wir unseren Raspberry Pi ein. Dazu werden wir zunächst das
Betriebssystem „Raspbian“ installieren. Dann befassen wir uns in diesem Kapitel noch mit
der SSH-Verbindung, damit nicht immer ein Bildschirm an den Raspberry Pi angeschlossen
werden muss. Wenn die SSH-Verbindung steht, richten wir noch den Remote Desktop
Verbindung ein, dass wir auch ein GUI zu erleichterten Bedienung bekommen. Zum Schluss
widmen wir uns noch einem WLan-Stick, um auf unseren Raspberry Pi auch kabellos darauf
zugreifen können.
Das Betriebssystem Wir haben uns für das Betriebssystem „Raspbian“ entschieden. Dieses Betriebssystem ist
ein speziell für den Raspberry Pi optimierte Linux-Version. Um „Raspbian“ zu installieren
downloaden wir uns das sogenannte NOOBS-Zipverzeichnis von der Herstellerseite:
http://www.raspberrypi.org/downloads
Hierbei ist darauf zu achten, dass hier die Vollversion und nicht die Lite-Version
heruntergeladen wird. Um das Betriebssystem erfolgreich zu installieren, benötigen wir ein
weiteres Programm. Dieses Programm nennt sich SDFormatter 4.0 und hat die Aufgabe
unsere SD-Speicherkarte, die wir für das Betriebssystem benötigen, zu formatieren. Es
genügt nicht aus, die Speicherkarte mit Windows zu formatieren! Das Programm kann man
unter folgendem Link auf der Herstellerseite downloaden:
https://www.sdcard.org/downloads/formatter_4
Nun können wir mit der Installation
von „Raspbian“ beginnen. Wir
formatieren zunächst unsere SD-
Speicherkarte. Dazu starten wir das
Programm SDFormatter und folgen
den Programmanweisungen.
Abbildung 2-1: SD-Speicherkarte formatieren
Kapitel2: Erste Schritte | 12
Nun übertragen wir die Zip-Datei auf die SD-Speicherkarte und extrahieren sie.
Beim Extrahieren muss darauf geachtet werden, dass die enthaltenden Dateien in keinen
Unterordner kopiert werden, sondern direkt auf die SD-Speicherkarte. Ansonsten bootet der
Raspberry Pi nicht von der SD-Karte. Wenn das Extrahieren erfolgreich war sollte das
Ergebnis anschließend wie folgt aussehen:
Abbildung 2-2: NOOBS-Zip auf die SD-Speicherkarte kopieren
Abbildung 2-3: NOOBS-Zip extrahieren
Kapitel2: Erste Schritte | 13
Nun ist die SD-Speicherkarte „startbereit“ und kann an den Raspberry Pi angeschlossen
werden.Des Weiteren benötigen wir für den ersten Bootvorgang eine Internetverbindung via
LAN, eine Tastatur (wahlweiße mit Maus) und eine Verbindung zu einem Bildschirm, in
diesem Fall via HDMI.
Abbildung 2-4: Das Extrahieren war erfolgreich
Abbildung 2-5: Das erste Booten des Raspberry Pi
Übertragung zum Bildschirm
Stromversorgung
SD-Karte
Internetverbindung
Funk-Maus/-Tastatur
Kapitel2: Erste Schritte | 14
Sobald eine Stromzufuhr vorhanden ist, bootet das System von Selbst. Es erscheint ein
Installations-Fenster, das so Aussieht, wie in Abbildung 2-6:
Dort wählen wir unser gewünschtes Betriebssystem. In unserem Fall wählen wir „Raspbian“
aus und klicken auf den Button „Install“. Wenn dieses Installations-Fenster nicht erscheint,
muss überprüft werden, ob die Dateien in einem Unterordner gelandet sind. Wenn das der
Fall ist, holen sie bitte die Dateien aus diesem Ordner und legen sie direkt auf die SD-
Speicherkarte.
Wenn die Installation erfolgreich war erscheint die Abbildung 2-7:
Das System macht dann einen automatischen Reboot. Nun
müssen noch ein paar Sachen eingestellt werden. Die
wichtigsten Einstellungen, die hier gemacht werden müssen
sind: einstellen der Sprache, sowie der Zeitzone und der
Tastatur, Festlegung eines neuen Passworts, das booten auf
das GUI und das Freischalten der SSH-Verbindung.
Abbildung 2-7: Installation
erfolgreich
Abbildung 2-8: Setup-Einstellungen
Abbildung 2-6: Installations-Fenster
Kapitel2: Erste Schritte | 15
Abbildung 2-10: PuTTY
Wenn sie diese Einstellungen gemacht haben, wählen sie „Finish“ und das System bootet
sich ein weiteres Mal neu. Nun sollte Abbildung 2-9 erscheinen. Wenn dies der Fall ist haben
sie die Installation des Betriebssystems erfolgreich abgeschlossen!
SSH-Verbindung Wichtig: Für diesen Schritt muss, wie oben beschrieben, die SSH-Verbindung aktiviert sein.
Ansonsten lässt der Raspberry Pi die Verbindung nicht zu!
Es wäre ja lästig, wenn man immer für den Raspberry Pi einen Bildschirm
bräuchte. Um einen Befehl von einem anderen Rechner auszuführen nutzen
den beliebten SSH-Client „PuTTY“. Dieses Programm stellt eine verschlüsselte
Verbindung (SSH = Secure Shell) zum Raspberry Pi her. PuTTY reicht leider
nur für eine Kommandozeile aus, wie manche Windows-Nutzer sie
noch von MS-DOS kennen werden. Um die GUI auf unseren Rechner
zu bekommen, nutzen wir einen remote Desktop, aber dazu später in diesem Kapitel mehr.
Zunächst laden wir uns das Programm unter folgendem Link herunter:
http://www.chip.de/downloads/PuTTY_129973
92.html
Dieses Programm benötigt keine Installation
und kann direkt verwendet werden. Beim
Aufrufen muss nun die IP des Pi‘s eingegeben
werden. Des Weiteren sollte überprüft
werden, ob der Port 22 eingetragen ist und
auch SSH ausgewählt ist. Die Eingabe kann
mit „Save“ mit einem eingegebenen Namen
abgespeichert werden. Wie man dieses
Programm nutzt dazu kommen wir ein
bisschen später.
Abbildung 2-9: Installation wurde erfolgreich abgeschlossen
Abbildung 2-11: Eine
Verbindung mit PuTTY
Kapitel2: Erste Schritte | 16
Abbildung 2-13: Import von Verbindungen
WinSCP WinSCP ist ein FTP-Client. FTP (File Transfer Protocol) ist ein Protokoll,
welches die Übertragung von Dateien in einem Netzwerk ermöglicht. Wir
wollen WinSCP benutzen um auf das Dateisystem des Raspberry Pi
zuzugreifen.
WinSCP lässt sich unter folgendem Link herunterladen:
http://www.chip.de/downloads/c1_downloads_hs_getfile_v1_16096134.html?t=1399218326&
v=3600&s=98e94ce38eaa541f8fe030bc7add35ec
Auch WinSCP nutzt eine SSH Verbindung. Deshalb ist es auch hier nötig, dass die SSH
beim Raspberry Pi aktiviert ist.
WinSCP bietet die Möglichkeit an
bestehende Verbindungen aus PuTTY
und Filezilla zu importieren. Da wird
PuTTY verwenden bietet es sich an
dies zu tun. Das entsprechende
Fenster (Abbildung 2-13) öffnet sich
sofort nach der Installation. Alternativ
kann man die Daten natürlich auch per
Hand eingeben. Um Verbindungen zu
einem späteren Zeitpunkt zu
importieren muss man lediglich auf
Werkzeuge klicken und danach auf
den ersten Eintrag im Popup-Menü:
„Verbindungsziele importieren“ klicken.
Abbildung 2-12: WinSCP
Abbildung 2-14: Hauptmenü
Kapitel2: Erste Schritte | 17
Abbildung 2-15: Das Dateiverzeichnis
Um sich nun mit einem Ziel zu verbinden müssen wir entweder einen Doppelklick auf eine
der Verbindungen von der linken Seite machen oder einen der Verbindungen auswählen und
dann auf Anmelden klicken. Hat man alles richtig gemacht sollte einem das folgende Fenster
(Abbildung 2-15) erscheinen.
Auf der linken Seite befindet sich das Dateiverzeichnis des Computers, auf dem man
WinSCP ausführt, auf der rechten Seite das des Ziels. Per Drag-and-Drop lassen sich nun
Dateien einfach verschieben/kopieren.
Remotedesktop Mit einem Remotedesktop kann man sich einen „Kopie“ eines Desktop eines anderen
Rechners anzeigen lassen. Der Raspberry Pi unterstützt eine solche Funktion und somit
benötigen nach dem Abschließen der Installation des Remotedesktops keinen Bildschirm
mehr, um die GUI anzeigen zu lassen. Die GUI hat einige Vorteile, wie z.B. das erleichterte
Einrichten der WLAN-Verbindung.
Wir booten den Raspberry Pi wie gewohnt mit einem Internetanschluss. Wenn er fertig
gebootet hat können wir uns mit PuTTY einwählen. Nun müssen einen Befehl zum
Downloaden und Installieren der Remote Desktop Software „XRDP“ eingeben.
sudo apt-get install xrdp
Nach einem kurzen Downloadvorgang fragt das System, ob wir die Software installieren
möchten. Wir bestätigen diese Frage mit „J“ (JA) und das Programm wird installiert.
Kapitel2: Erste Schritte | 18
Nun können wir das Programm sofort einmal testen. Dazu rufen wir auf unserem Windows-
Rechner das Programm „Remotedesktopverbindung“ auf und geben unsere IP vom
Raspberry Pi ein. Es sollte sich nun ein Fenster öffnen, indem unser Benutzername und
Passwort vom Pi abgefragt wird. Nachdem wir diese eingegeben haben, sollte die GUI des
Betriebssystems, wie in Abbildung 2-17 gezeigt, erscheinen.
Einrichten der WLAN-Verbindung Zur Einrichtung des WLANs schließen wir einfach den WLAN-Adapter an
den Raspberry Pi an. Der von uns verwendeten WLAN-Adapter wird
sofort erkannt und eine manuelle Installation von Treibern ist daher nicht
notwendig. Dies lässt sich auch überprüfen, indem man den
Befehl dmsgeingibt.
Nun muss der WLAN-Adapter noch konfiguriert
werden. Dazu öffnen wir die wpa_gui
(Abbildung 2-19) über die Schaltfläche auf dem
Desktop. Mit einem Klick auf „Scan“ öffnet sich
ein neues Fenster (Abbildung 2-20), in
welchem die verfügbaren Netzwerke angezeigt
werden.
Abbildung 2-19: Hauptfenster der wpa_gui
Abbildung 2-20: Die verfügbaren Netzwerke
Abbildung 2-16:
Remotedesktopverbindung aufbauen
Abbildung 2-17: GUI des Betriebssystems
Abbildung 2-18: WLAN
Kapitel2: Erste Schritte | 19
Hier kann man nun das gewünschte
Netzwerk auswählen. Darauf hin öffnet
sich ein weites Fenster, wo man die
für das Netzwerk spezifischen
Einstellungen treffen kann.Nach einem
Klick auf„Add“ am unteren Fensterrand
kann man im Hauptfenster auf
„Connect“ klicken und man ist mit dem
gewünschten Netzwerk verbunden,
sofern die Einstellungen, wie zum
Beispiel der Sicherheitsschlüssel,
korrekt sind.
Abbildung 2-21: Legoroboter-Netzwerk
Kapitel 3: Die Entwicklungsumgebung | 20
Kapitel 3
Die Entwicklungsumgebung
Nun wollen wir uns ein wenig mit der Entwicklungsumgebung beschäftigen. Da wir im
Unterricht Eclipse nutzen, wollen wir es bei diesem Projekt auch verwenden. Natürlich
können auch alle anderen Entwicklungsplattformen genutzt werden, jedoch sehen diese ein
wenig anders aus.
Installation von Eclipse Zunächst downloaden wir uns die neuste Version von Eclipse herunter. In unserem Fall ist
das die Version „Kepler“. Diese kann unter folgendem Link heruntergeladen
werden:http://www.eclipse.org/downloads/download.php?file=/technology/epp/downloads/rel
ease/kepler/SR2/eclipse-standard-kepler-SR2-win32-x86_64.zip&mirror_id=1190 (03.05.14)
Das Programm kommt als Zip-Datei, die noch entpackt werden muss. Dann muss einfach
die eclipse.exe-Datei ausgeführt werden, um das Programm zu starten. Nun möchte das
Programm eine sogenannte „workespace“ festlegen. Die „workspace“ ist der Ordner, wo alle
Programme abgelegt werden. Wir wählen nun ein Verzeichnis und fertig ist die Installation
von Eclipse.
Jars einbinden Manchmal ist es notwendig, Klassen von anderen Entwicklern in das eigene Projekt
einzubinden. Dazu bekommt man vom Entwickler eine Jar-Datei, die nur noch in das Projekt
eingebunden werden muss, damit die .class-Datei richtig kompiliert werden kann. Ein
angenehmer Nebeneffekt ist, dass Eclipse nun auch diese Befehle mit der
Autovervollständigung vollenden kann.
Um Jars einbinden zu können müssen die Jar-Dateien zunächst ins Projekt kopiert werden.
Man kann die Dateien direkt in das Projekt ziehen
oder auch erst ein Ordner erstellen, der für Jar-
Dateien zuständig ist. Wegen der Übersicht
werden wir einen Ordner mit dem Namen „lib“
anlegen und die Dateien dort rein kopieren.
Wir gehen mit rechten Maustasten auf unser
Projekt. Nun navigieren wir unter „New“ zu
„Folder“ und erstellen damit einen neuen Ordner.
Diesen Ordner nennen wir „lib“ und klicken auf
„Finish“.
Abbildung 3-1: Neuen Ordner erstellen
Kapitel 3: Die Entwicklungsumgebung | 21
Nun kopieren wir die gewünschten Jar-Dateien und fügen sie
mit Rechtsklick und „Paste“ ein. Bei Eclipse öffnet sich nun ein
Fenster, was fragt, ob wir die Dateien dort rein kopieren
möchten oder nur eine Verknüpfung erstellen wollen. Wir
möchten die Dateien in diesem Ordner liegen haben und
daher wählen wir „Copy Files“ und auf „OK“.
Wir haben uns bei unserem Beispiel für die Pi4J-Jars
entschieden. Nach dem kopieren liegen die Dateien nun, wie in
Abbildung 3-3 gezeigt, in dem Ordner „lib“.
Nun müssen alle Jar-Dateien markiert werden. Wir gehen mit
Rechtsklick auf die Dateien und wählen unter „Build Path“ „Add
to Build Path“. Damit
werden die Dateien
zum „Bauplan“
hinzugefügt. Das
bedeutet, dass Java
nun weiß, wie es
sich verhalten soll,
wenn wir mit den
Klassen aus den Jar-Dateien etwas machen.
Nun haben wir die Jar-Dateien erfolgreich zu unserem Projekt hinzugefügt und können nun
verwendet werden.
Windows Builder installieren Zur besseren Gestaltung der GUI wollen wir den
kostenlosen Windows Builder nutzen. Dies ist ein Plug-
In für Eclipse und lässt sich leicht in Eclipse einbinden.
Um das Plug-In zu installieren wählen wir in Eclipse
unter „Help“ „Install New Software“
Es wird ein Fenster zum Installieren von neuer Software
geöffnet. Im Feld „Work with:“ tragen wir folgenden Link
ein.
http://download.eclipse.org/windowbuilder/WB/release/R201309271200/4.3/ (29.05.2014 |
11:38)
Abbildung 3-1: Install New Software…
Abbildung 3-2: Die Dateien kopieren
Abbildung 3-3: Die Jar-Dateien
Abbildung 3-4: Die Jar-Dateien
Kapitel 3: Die Entwicklungsumgebung | 22
Nun müssen wir die Pakete auswählen, die wir installieren möchten. Wir wählen alle
vorhandenen Pakete mit „Select All“ aus.
Danach fahren wir mit „Next“ fort. Eclipse zeigt dann
nochmal an, welche Pakete installiert werden. Wir
gehen ein weiteres Mal mit „Next“ weiter. Schließlich
müssen noch die Lizenzbedingungen akzeptiert
werden und Windows Builder wird installiert.
Bevor Windows Builder genutzt werden kann muss
Eclipse einmal neu gestartet werden.
Nun ist die Installation abgeschlossen.
Abbildung 3-2: Link eintragen
Abbildung 3-3: Pakete auswählen
Abbildung 3-4: Windows Builder wird
installiert
Abbildung 3-5: Eclipse neu starten
Kapitel 4: Motorenansteuern | 23
Kapitel 4
Motorenansteuern
Im folgenden Kapitel werden wir uns mit dem Motorenansteuern beschäftigen.
Pi4J-Installation Um die GPIO-Pins auf dem Raspberry Pi mit Java anzusteuern, benötigen wir zunächst das
Zusatzprogramm Pi4J. Die folgenden Befehle können mit PuTTY auf dem Pi ausgeführt
werden.
Zunächst laden wir uns die neuste Pi4J-Version mit folgendem Befehl herunter:
wget http://pi4j.googlecode.com/files/pi4j-0.0.5.deb
Nun führen wir die automatische Installation mit diesem Befehl durch:
sudo dpkg -i pi4j-0.0.5.deb
Nun können wir kontrollieren, ob die Installation erfolgreich war, indem wir überprüfen, ob
diese Verzeichnisse vorhanden sind. Dies tun wir, indem wir mit WinSCP zu diesem Pfad
gehen.
Abbildung 4-1: Die Installation von Pi4J war erfolgreich
Kapitel 4: Motorenansteuern | 24
Ein Java-Programm kompilieren Wenn wir nun ein Java Programm, in dem wir Pi4J verwendet haben, müssen wir nun immer
mit der Library kompilieren. Wir übertragen mit WinSCP unsere .java Datei von unserem
Programm in das gewünschte Ziel-Verzeichnis.
Danach können wir diese Datei kompilieren, indem wir mit PuTTY zu diesem Verzeichnis
navigieren und den folgenden Befehl ausführen:
javac -classpath .:classes:/opt/pi4j/lib/'*' ...
Die drei Punkte müssen natürlich noch mit [Dateiname].java ausgetauscht werden, damit
der Rechner weiß, welche Datei er kompilieren soll. Das Kompilieren dauert durch die
geringe Rechenleistung ein wenig länger als erwartet…
Ausführen eines Java-Programms Wen das Programm kompiliert wurde kann es Ausgeführt werden. Hier gilt das Gleiche, wie
beim kompilieren. Die Pi4J-Library muss mit eingebunden werde. Daher führt man solche
Programme mit diesem Befehl aus:
sudo java -classpath .:classes:/opt/pi4j/lib/'*' ...
Die drei Punkte müssen diesmal nur mit dem Dateinamen ausgetaucht werden und das
Programm läuft!
Abbildung 4-2: Übertragen der .java Datei
Kapitel 4: Motorenansteuern | 25
Abbildung 4-3: Die Kontakte
eines Motors
Anschluss der Motoren Nun kommen wir zum Anschließen der Motoren an die
Steuerplatine. Die machen wir wie folgt:
Unsere Motorenanschlüsse besitzen vier Kontakte (siehe
Abbildung 4-3). Für unsere Zwecke benötigen wir C1 und
C2. Diese Beiden Kontakte sind unser Minus- und Plus-Pol.
Wenn wir nun den Motor in einen Stromkreislauf einbinden,
dann dreht der Motor, je nachdem wie gepolt ist, nach vorne
oder nach hinten.
Wir müssen nun einen Kontakt mit diesen Kontaktplättchen
herstellen. Wir haben uns hier für Male-Jumperkabel
entschieden, da diese einen sehr kleinen Kontakt besitzen.
Abbildung 4-4 zeigt die Verbindung mit den Jumperkabeln. Zu
beachten ist noch, dass die Jumperkabel mit den beiden
Kontaktplättchen, wie auf dem Bild verbunden sind. Sonst
funktioniert der ganze Aufbau nicht.
Jetzt kommt unsere Steuerplatine zum Einsatz:
Diese Platine besitzt jeweils einen Plus- und Minuspol für zwei Motoren. Wenn sich später
beim Ansteuern der Motoren herausstellen sollte, dass die Motoren falsch herum drehen,
muss der angesprochene Motor nur umgepolt werden.
Abbildung 4-4: Verbindung
mit Jumperkabel
Abbildung 4-5: Die Steuerplatine
Kapitel 4: Motorenansteuern | 26
Abbildung 4-7: Pinbelegung
Die Abbildung 4-6 zeigt, wie die einzelnen
Komponenten miteinander verbunden werden müssen.
Zunächst wird der 5V-Anschluss (PIN 2) des
Raspberry Pi´s mit dem 5V-Inputs (siehe Abbildung 4-
5) der Platine verbunden. Danach folgt das Verbinden
des Ground-Anschlusses an der Platine (siehe
Abbildung 4-5) mit dem PIN 6 des Raspberry Pis, der
ebenfalls die Ground ist. Der Batterieclip wird ebenfalls
an die Platine angeschlossen. Der Pluspol an den
12V-Input der Platine (siehe Abbildung 4-5) und der
Minuspol ebenfalls an den Ground-Anschluss der
Platine. Nun müssen nur noch Pin 1-4 der Platine mit
jeweils einem GPIO-Pin verbunden werden. Wir
verbinden IN 1 mit Pin 11, IN 2 mit Pin 13, IN 3 mit Pin
19 und IN 4 mit Pin 21. Die GPIO-Bezeichnungen
variieren bei verschiedenen Schemata und daher
nennen wir hier nur die Pin-Nummer und nicht die Bezeichnungen.
Erstes Ansteuern Nun können wir die Motoren das erste Mal ansteuern, wo wir sehen werden, ob wir die
Motoren richtig verbunden haben. Wir schreiben das Programm in eine Java-Datei. Danach
navigieren wir in unsere „Workspace“ von Eclipse und übertragen die .java Datei via WinSCP
auf den Raspberry Pi. Wir navigieren auf dem Pi mit der Kommandozeile via PuTTY zur
Datei und kompilieren diese, wie in diesem Kapitel schon beschrieben. Wenn das passiert ist
kann das Programm ausgeführt werden und die Motoren laufen! Auf der nächsten Seite
haben wir den Programmcode eingefügt und werden ihn kurz erläutern.
Abbildung 4-6: Der Anschluss der Komponenten
Kapitel 4: Motorenansteuern | 27
import com.pi4j.io.gpio.GpioController; import com.pi4j.io.gpio.GpioFactory; import com.pi4j.io.gpio.GpioPinDigitalOutput; import com.pi4j.io.gpio.PinState; import com.pi4j.io.gpio.RaspiPin;
publicclass ErstesAnsteuern { publicstaticvoid main(String[] args) { //erschafft GPIO-Controller final GpioController gpio = GpioFactory.getInstance(); //Pin-Array GpioPinDigitalOutput[] pins = new GpioPinDigitalOutput[4]; //Pins dem Array zuweisen und auf "low" setzen
pins[0] = gpio.provisionDigitalOutputPin(RaspiPin.GPIO_00, "Motor1Pin2", PinState.LOW); //Board-Nr=11
pins[1] = gpio.provisionDigitalOutputPin(RaspiPin.GPIO_02, "Motor1Pin2", PinState.LOW); //Board-Nr=13
pins[2] = gpio.provisionDigitalOutputPin(RaspiPin.GPIO_12, "Motor1Pin2", PinState.LOW); //Board-Nr=19
pins[3] = gpio.provisionDigitalOutputPin(RaspiPin.GPIO_13, "Motor1Pin2", PinState.LOW); //Board-Nr=21
System.out.println("Ansteuerung startet"); for (int i = 0; i <= 5; i++) { for (int j = 0; j <= 3; j++) { System.out.println((j+1)+"Pin"); //Pin auf "high" setzen pins[j].high(); //1 Sekunde drehen lassen try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } //Pin auf "low" setzen pins[j].low(); //1 Sekunde Stillstand try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } //GPIO abschalten gpio.shutdown();
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 68
69
Kapitel 4: Motorenansteuern | 28
System.out.println("Ansteuerung wurde beendet"); }
}
In Zeile 13 erschaffen wir zunächst den GPIO-Controller. Dies ist die Aufforderung mit den
Pins zu kommunizieren. Danach wird ein Pin-Array erzeugt und die verschiedenen Pins
initialisiert. Dabei wird die Pin-Nummer von Pi4J übergeben, damit klar ist welcher Pin
gemeint ist(Abbildung 4-7). Des Weiteren werden noch ein Name für den Pin und der
Ausgangsstatus „low“ übergeben.
Die zwei Zustände, die ein GPIO-Pin haben kann, sind „low“ und „high“. Bei „low“ liegt keine
Spannung auf dem Pin. Wenn der Pin auf „high“ gesetzt wird, wird geringe Spannung auf
den Pin gelegt.
Nun gibt das Programm „Ansteuern startet!“ in der Konsole aus. Nun werden die vier Pins
5mal für jeweils eine Sekunde nacheinander angesteuert.
Steuerung per Konsole In dem ersten Programm kann man auf die Steuerung nur einflussnehmen, indem man den
Ablauf direkt im Programmcode ändert. Dies ist natürlich nicht sehr praktisch. Als nächsten
Schritt möchten wir die Steuerung nun über die Konsole realisieren.
import Tools.IOTools;
import com.pi4j.io.gpio.GpioController;
import com.pi4j.io.gpio.GpioFactory;
import com.pi4j.io.gpio.GpioPinDigitalOutput;
import com.pi4j.io.gpio.PinState;
import com.pi4j.io.gpio.RaspiPin;
publicclass SteuernMitKonsole {
publicstaticvoid main(String[] args) {
String eingabe;
char ende;
final GpioController gpio = GpioFactory.getInstance();
GpioPinDigitalOutput[] pins =newGpioPinDigitalOutput[4];
pins[0] =
gpio.provisionDigitalOutputPin(RaspiPin.GPIO_00, "Motor1Pin2",
PinState.LOW); //Board-Nr=11, links vor
pins[1] =
gpio.provisionDigitalOutputPin(RaspiPin.GPIO_02, "Motor1Pin2",
PinState.LOW); //Board-Nr=13, links zurueck
pins[2] =
gpio.provisionDigitalOutputPin(RaspiPin.GPIO_12, "Motor1Pin2",
PinState.LOW); //Board-Nr=19, rechts zurueck
pins[3] =
gpio.provisionDigitalOutputPin(RaspiPin.GPIO_13, "Motor1Pin2",
PinState.LOW); //Board-Nr=21, rechts vor
System.out.println("Ansteuerung startet");
64
65
66
67
68
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
Kapitel 4: Motorenansteuern | 29
do {
eingabe = IOTools.readString("Befehl: ");
switch (eingabe) {
case"vor":
pins[0].high();
pins[3].high();
break;
case"zurueck":
pins[1].high();
pins[2].high();
break;
case"links":
pins[3].high();
break;
case"rechts":
pins[0].high();
break;
case"rechts drehen":
pins[0].high();
pins[2].high();
break;
case"links drehen":
pins[1].high();
pins[3].high();
break;
default:
System.out.println("Eingabefehler");
break;
}
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
for (int i = 0; i < pins.length; i++) {
pins[i].low();
}
} while (true);
}
}
Die Initialisierung der GPIO-Pins übernehmen wir aus unserem ersten Programm.Nun
ersetzen wir die For-Schleifen, die nacheinander die Pins auf „High“ gesetzt hat, mit einer
Dauerschleife. In der Schleife fragen wir zunächst einen Befehl ab. Die möglichen Befehle
lauten „vor“, „zurueck“, „links“, „rechts“, „rechts drehen“ und „links drehen“. In dem darauf
folgenden switch-case Statement wird überprüft welcher Befehl eingegeben wurde. Dabei
werden die Motoren der Tabelle 4-1 entsprechend geschaltet.
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
Kapitel 4: Motorenansteuern | 30
Befehl Motor 1 Motor 2
vor
zurueck
links
rechts
links drehen
rechts drehen
Danach pausiert das Programm für 2 Sekunden, während sich die Motoren drehen. Wenn
die Zeit vergangen ist werden alle Pins werden wieder auf „low“ gesetzt und die Motoren
stoppen.
Dieser Vorgang wiederholt sich so lange, bis das Programm beendet wird.
Ansteuerung per Tastatur Eine angenehme Steuerung bietet die Steuerung über die Konsole allerdings noch nicht.
Eine bessere Möglichkeit bietet die Steuerung über die Tasten der Tastatur.
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JFrame;
import com.pi4j.io.gpio.GpioController;
import com.pi4j.io.gpio.GpioFactory;
import com.pi4j.io.gpio.GpioPinDigitalOutput;
import com.pi4j.io.gpio.PinState;
import com.pi4j.io.gpio.RaspiPin;
publicclass Tastatursteuerung{
static GpioPinDigitalOutput[] pins = new
GpioPinDigitalOutput[4];
publicstaticvoid main(String[] args) {
final GpioController gpio = GpioFactory.getInstance();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Tabelle 4-1: Motoransteuerung
Kapitel 4: Motorenansteuern | 31
pins[0] = gpio.provisionDigitalOutputPin(RaspiPin
.GPIO_00, "Motor1Pin2", PinState.LOW);
//Board-Nr=11,GPIO=17, links vor
pins[1] = gpio.provisionDigitalOutputPin(RaspiPin
.GPIO_02, "Motor1Pin2", PinState.LOW);
//Board-Nr=13,GPIO=21, links zurueck
pins[2] = gpio.provisionDigitalOutputPin(RaspiPin
.GPIO_12, "Motor1Pin2", PinState.LOW);
//Board-Nr=19,GPIO=10, rechts zurueck
pins[3] = gpio.provisionDigitalOutputPin(RaspiPin
.GPIO_13, "Motor1Pin2", PinState.LOW);
//Board-Nr=21,GPIO=9, rechts vor
JFrame jf = newJFrame(“Fenstertitel”);
jf.setVisible(true);
jf.setSize(500, 300);
jf.setDefaultCloseOperation(EXIT_ON_CLOSE);
jf.setLocationRelativeTo(null);
jf.setResizable(true);
jf.addKeyListener(new Keyhandler());
jf.setFocusable(true);
}
privateclass KeyHandler implements KeyListener {
publicvoid keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_W) {
pins[0].high();
pins[3].high();
}
if (e.getKeyCode() == KeyEvent.VK_S) {
pins[1].high();
pins[2].high();
}
if (e.getKeyCode() == KeyEvent.VK_A) {
pins[3].high();
}
if (e.getKeyCode() == KeyEvent.VK_D) {
pins[0].high();
}
if (e.getKeyCode() == KeyEvent.VK_Q) {
pins[1].high();
pins[3].high();
}
if (e.getKeyCode() == KeyEvent.VK_E) {
pins[0].high();
pins[2].high();
}
}
publicvoid keyReleased(KeyEvent e) {
if (e.getKeyCode()== KeyEvent.VK_W
||e.getKeyCode() ==KeyEvent.VK_S
||e.getKeyCode() == KeyEvent.VK_A
||e.getKeyCode() == KeyEvent.VK_D
||e.getKeyCode() == KeyEvent.VK_Q
||e.getKeyCode() == KeyEvent.VK_E) {
for (int i = 0; i <pins.length; i++) {
pins[i].low();
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
Kapitel 4: Motorenansteuern | 32
}
}
}
publicvoid keyTyped(KeyEvent e) {
}
}
}
Für die Abfrage ob und wenn ja, welche Taste gedrückt ist verwenden wir das Interface
KeyListener. Dieses implementieren wir in die innere Klasse KeyHandler. Das Interface
KeyListener besteht aus drei Methoden: keyPressed(KeyEvent e), keyReleased(KeyEvent e)
und keyTyped(KeyEvent e). Wir benötigen jedoch nur die Methoden keyPressed() und
keyReleased(). Die Methode keyPressed() wird ausgeführt wenn eine Taste gedrückt wird.
Jetzt müssen wir nur noch herausfinden, weche Taste gedrückt wird. Dies machen wir,
indem wir die Methode getKeyCode() auf den Paramter e anwenden. Die Schaltung der
Motoren erfolgt wieder nach der Tabelle 4-1, nur dass die Befehle jetzt durch die Tasten
ersetzt werden. Der vor-Befehl entspricht der Taste W, der zurueck-Befehl der Taste S, links
entspricht A, rechts D, rechts drehen E und links drehen Q.
Die Methode keyReleased() wird ausgeführt wird ausgeführt wenn eine Taste losgelassen
wird. Wird eine der Tasten W, A, S, D, Q, E losgelassen so sollen die Motoren stoppen.
Jetzt müssen wir noch dafür sorgen, dass die Methoden auch ausgeführt werden. Dafür
müssen wir einem JFrame ein Objekt unserer KeyHandler-Klasse als KeyListener
übergeben, indem wir die Methode addKeyListener() aufrufen (Zeile 44). Unser KeyListener
funktioniert allerdings nur, wenn der Fokus auf dem JFrame ist. Dies ist standartmäßig nicht
der Fall. Deshalb setzen wir in Zeile 45 noch den Fokus auf den JFrame.
Nun können wir den Legoroboter per Tastatur steuern. Wichtig ist dabei, dass wir das
Programm mit dem Remote Desktop ausführen, da PuTTY nur Zugriff auf die Konsole hat.
Haben wir alles richtig gemacht so sollten wir jetzt ein leeres Fenster sehen.
87
88
89
90
91
92
93
94
95
96
97
98
Kapitel 5: Server und Client | 33
Kapitel 5
Server und Client
Weder das Ansteuern mit der Konsole, noch das Ansteuern per Tastatur über den
Remotedesktop sind wirklichelegante Lösungen. Bei der Konsoleneingabe könnte man zwar
noch einiges verbessern, wie zum Beispiel die Zeit mit eingeben, wie lange sich der Motor
drehen soll. Jedoch würde eine Konsoleneingabe auf die Dauer nicht wirklich schnell sein,
da immer wieder Befehle eingegeben werden müssen. Das Tastaturansteuern via
Remotedesktop kann man wegen der geringen Leistung des Raspberry Pis vergessen.
Da kam uns die Idee, dass man auf dem Raspberry Pi ein Programm laufen lassen könnte,
das darauf wartet von einem anderen Programm einen Befehl zu bekommen. Daraus soll so
ein Art „Server und Client“ entstehen.
Server und Client Beispiel Für unser Vorhaben wollen wir mit Socket und ServerSocket arbeiten. Zum besseren
Verständnis, werden wir das Prinzip an einem bzw. zwei Programme, die miteinander
kommunizieren, erläutern. Der Client (Socket) wird eine Nachricht an den Server
(ServerSocket) senden und dieser wird sie dann auf der Konsole ausgeben.
Server:
//Hier darf kein Package genannt werden
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
publicclass ServerBeispiel {
publicstaticvoid main(String[] args) {
try {
//Server erzeugt mit dem Port 5555
ServerSocket server = new ServerSocket(5555);
System.out.println("Server gestartet!");
System.out.println("Warten auf Client");
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
Kapitel 5: Server und Client | 34
//Client erstellen und Server erwartet einen Client
Socket client = server.accept();
System.out.println("Client akzeptiert");
//Streams
OutputStream out = client.getOutputStream();
PrintWriter writer = new PrintWriter(out);//In
unserem Fall unnoetig da nur der Inputstream genutzt wird
InputStream in = client.getInputStream();
BufferedReader reader = new BufferedReader(new
InputStreamReader(in));
//----------------------------------------------
//InputStream auslesen
String s = null;
while ((s = reader.readLine()) != null) {
System.out.println(s);
}
reader.close();
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Client:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import Tools.IOTools;
publicclass Client {
publicstaticvoid main(String[] args) {
String ip = IOTools.readString("Bitte die IP-Adresse
eingeben: ");
try {
//Client erstellen
Socket client = new Socket(ip , 5555);
System.out.println("Client wurde gestartet!");
//Streams
OutputStream out = client.getOutputStream();
PrintWriter writer = new PrintWriter(out);
InputStream in = client.getInputStream();
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
Kapitel 5: Server und Client | 35
BufferedReader reader = new BufferedReader(new
InputStreamReader(in));//In unserem Fall unoetig,
da nut OutputStream genutzt wird
//----------------------------------------------
//Nachricht schreiben
String text = IOTools.readLine("Bitte geben sie die
Nachricht ein: ");
writer.write(text + "\n");
//Writer aktualisieren
writer.flush();
//Writer und Reader beendet
writer.close();
reader.close();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Zunächst wird der Server gestartet. Es wird ein Server mit dem Port 5555 erstellt. Nun wartet
das Programm, dass es vom Client angesprochen wird. Der Client wird nun gestartet und der
Server merkt, dass der Client gerne eine Verbindung mit ihm eingehen würde. Der Server
akzeptiert den Client und wartet nun auf eine Nachricht. Nun kann der User des Clients auf
die Frage nach der Nachricht etwas eingeben und der Server liest diese aus. Für diesen
Vorgang wird der Input- und Outputstream benötigt. Beim Client ist der Inputstream unnötig,
genauso wie der Outpustream beim Server. Da es hier aber nur ums Prinzip geht, haben wir
die Angesprochenen Stream einfach erst einmal im Programm gelassen.
Server-Anpassungen Nun haben wir den Server für unsere Bedürfnisse angepasst:
//Hier darf kein Package genannt werden
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import Tools.IOTools;
import com.pi4j.io.gpio.GpioController;
import com.pi4j.io.gpio.GpioFactory;
import com.pi4j.io.gpio.GpioPinDigitalOutput;
import com.pi4j.io.gpio.PinState;
import com.pi4j.io.gpio.RaspiPin;
import com.pi4j.system.NetworkInfo;
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Kapitel 5: Server und Client | 36
publicclass Server {
static GpioPinDigitalOutput[] pins = new
GpioPinDigitalOutput[4];
publicstaticvoid main(String[] args) throws
InterruptedException{
//GPIO Controller erzeugen
final GpioController gpio = GpioFactory.getInstance();
//Pins dem Array zuweisen und auf low stellen
pins[0] =
gpio.provisionDigitalOutputPin(RaspiPin.GPIO_00,
"Motor1Pin2", PinState.LOW); //Board-Nr=11, links vor
pins[1] =
gpio.provisionDigitalOutputPin(RaspiPin.GPIO_02,
"Motor1Pin2", PinState.LOW); //Board-Nr=13, links zurueck
pins[2] =
gpio.provisionDigitalOutputPin(RaspiPin.GPIO_12,
"Motor1Pin2", PinState.LOW); //Board-Nr=19,rechts zurueck
pins[3] =
gpio.provisionDigitalOutputPin(RaspiPin.GPIO_13,
"Motor1Pin2", PinState.LOW); //Board-Nr=21, rechts vor
try {
System.out.println("Server gestartet . . .");
//Port fuer den Server waehlen
int port = IOTools.readInteger("Bitte waehlen Sie
einen Port: ");
//Server erstellt mit dem Port 5555
ServerSocket host = new ServerSocket(port);
System.out.println("Server gehostet . . .");
for (String ipAddress :
NetworkInfo.getIPAddresses())
System.out.println("Der Server ist nun unter der IP
" + ipAddress + " und dem Port " + port + "
erreichbar . . .");
System.out.println("Warte auf Client . . .");
//Auf Client warten und akzeptieren
Socket client = host.accept();
System.out.println("Client akzeptiert . . .");
//Streams
OutputStream out = client.getOutputStream();//Zum
senden an den Client
PrintWriter writer = new PrintWriter(out);
InputStream in = client.getInputStream();//Zum
Empfangen vom Server
BufferedReader reader = new BufferedReader(new
InputStreamReader(in));
//---------------------------------------
while (true) {
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
Kapitel 5: Server und Client | 37
//InputStream auslesen
switch (reader.read()) {
//Befehl verarbeiten
case 1: //VOR
System.out.println("Faehrt vor . . .");
pins[0].high();
pins[3].high();
while (reader.read() == 1) {
}
break;
case 2: //Zurueck
System.out.println("Faehrt zurueck . .
.");
pins[1].high();
pins[2].high();
while (reader.read() == 2) {
}
break;
case 3: //Links
System.out.println("Faehrt nach links .
. .");
pins[3].high();
while (reader.read() == 3) {
}
break;
case 4: //Rechts
System.out.println("Faehrt nach rechts .
. .");
pins[0].high();
while (reader.read() == 4) {
}
break;
case 5://LinksDrehen
System.out.println("Dreht sich nach
links . . .");
pins[1].high();
pins[3].high();
while (reader.read() == 5) {
}
break;
case 6://RechtsDrehen
System.out.println("Dreht sich nach
rechts . . .");
pins[0].high();
pins[2].high();
while (reader.read() == 6) {
}
break;
case 0:
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
Kapitel 5: Server und Client | 38
System.out.println("Gestoppt . . .");
for (int i = 0; i <pins.length; i++) {
pins[i].low();
}
while (reader.read() == 0) {
}
break;
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
Das Programm ist ähnlich, wie das Programm „Steuern mit Konsole“, aufgebaut. Jedoch bekommt es die Befehle nicht mehr über die Konsoleneingaben des Benutzers, sondern von dem Client. Die Auswertung finden genau gleich statt, wie in dem eben genannten Programm.
Der Client Nun haben wir einen etwas aufwendigen Client begonnen. Zunächst werden hier die
Anfänge gezeigt. Später wird der Client noch durch eine Webcam und einen Joystick
erweitert.
Launcher:
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.ImageIcon;
import javax.swing.JTextField;
import javax.swing.JLabel;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JButton;
import java.awt.Color;
publicclass Launcher extends JFrame implements ActionListener,
KeyListener{
private JPanel contentPane;
private JButton btnVerbinden;
private JTextField txtIp;
private JTextField txtPort;
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
Kapitel 5: Server und Client | 39
private JLabel lblHintergrundLauncher;
private JLabel lblIpadresse;
private JLabel lblPort;
privatestatic Launcher launcher;
publicstaticvoid main(String[] args) {
//Launcher aufrufen
EventQueue.invokeLater(new Runnable() {
publicvoid run() {
try {
launcher = new Launcher();
launcher.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public Launcher() {
//Erschafft die GUI
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 450, 328);
setLocationRelativeTo(null);
setResizable(false);
setTitle("Launcher");
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(null);
txtIp = new JTextField();
txtIp.setBounds(10, 268, 197, 20);
contentPane.add(txtIp);
txtIp.addKeyListener(this);
txtIp.setColumns(10);
txtPort = new JTextField();
txtPort.setBounds(217, 268, 113, 20);
contentPane.add(txtPort);
txtPort.addKeyListener(this);
txtPort.setColumns(10);
lblIpadresse = new JLabel("IP-Adresse");
lblIpadresse.setForeground(Color.WHITE);
lblIpadresse.setBounds(10, 249, 197, 14);
contentPane.add(lblIpadresse);
lblPort = new JLabel("Port");
lblPort.setForeground(Color.WHITE);
lblPort.setBounds(217, 249, 46, 14);
contentPane.add(lblPort);
btnVerbinden = new JButton("Verbinden");
btnVerbinden.setBounds(335, 265, 99, 23);
btnVerbinden.addActionListener(this);
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
Kapitel 5: Server und Client | 40
contentPane.add(btnVerbinden);
lblHintergrundLauncher = new JLabel();
lblHintergrundLauncher.setBounds(0, 0, 450, 300);
lblHintergrundLauncher.setIcon(new
ImageIcon(Hauptfenster.class.getResource("/HintergrundLauncher.png"))
);
contentPane.add(lblHintergrundLauncher);
}
//---KeyListener---
publicvoid keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ENTER){
btnVerbinden.doClick();
}
}
publicvoid keyTyped(KeyEvent e) {
}
publicvoid keyReleased(KeyEvent e) {
}
//-------------------
//---ActionListener---
publicvoid actionPerformed(ActionEvent e) {
if (e.getSource() == btnVerbinden) {
//Launcher schließen
launcher.dispose();
//GUI starten
EventQueue.invokeLater(new Runnable() {
publicvoid run() {
try {
Hauptfenster frame = new
Hauptfenster(txtIp.getText(),txtPort.getText());
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
//----------------------
}
Hauptfenster:
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.ImageIcon;
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
1
2
3
4
5
6
7
Kapitel 5: Server und Client | 41
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
publicclass Hauptfenster extends JFrame{
finaldoubleversion = 1.0;
privatestatic JPanel contentPane;
private JButton btnVor;
private JButton btnZurueck;
private JButton btnLinks;
private JButton btnRechts;
private JButton btnLinksDrehen;
private JButton btnRechtsDrehen;
private JLabel hintergrund;
private JLabel roterPfeil1;
private JLabel roterPfeil2;
private JLabel gruenerPfeil1;
private JLabel gruenerPfeil2;
private JLabel lblVersion;
private JMenuBar menuBar;
private JMenu mnDatei;
private JMenu mnOptionen;
private JMenu mnInfo;
private JMenuItem mntmBeenden;
private JMenuItem mntmKeyOptionen;
private JMenuItem mntmCredits;
private Verbindung verbindung;
privatestatic Key keyVor; //1 beim Senden
privatestatic Key keyZurueck; //2 beim Senden
privatestatic Key keyLinks; //3 beim Senden
privatestatic Key keyRechts; //4 beim Senden
privatestatic Key keyLinksDrehen; //5 beim Senden
privatestatic Key keyRechtsDrehen;//6 beim Senden
//Getter & Setter von den Keys
publicstaticvoid setKeyVor(Key newKey){
Hauptfenster.keyVor = newKey;
}
publicstatic Key getKeyVor(){
returnkeyVor;
}
publicstatic Key getKeyZurueck() {
returnkeyZurueck;
}
publicstaticvoid setKeyZurueck(Key keyZurueck) {
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
Kapitel 5: Server und Client | 42
Hauptfenster.keyZurueck = keyZurueck;
}
publicstatic Key getKeyLinks() {
returnkeyLinks;
}
publicstaticvoid setKeyLinks(Key keyLinks) {
Hauptfenster.keyLinks = keyLinks;
}
publicstatic Key getKeyRechts() {
returnkeyRechts;
}
publicstaticvoid setKeyRechts(Key keyRechts) {
Hauptfenster.keyRechts = keyRechts;
}
publicstatic Key getKeyLinksDrehen() {
returnkeyLinksDrehen;
}
publicstaticvoid setKeyLinksDrehen(Key keyLinksDrehen) {
Hauptfenster.keyLinksDrehen = keyLinksDrehen;
}
publicstatic Key getKeyRechtsDrehen() {
returnkeyRechtsDrehen;
}
publicstaticvoid setKeyRechtsDrehen(Key keyRechtsDrehen) {
Hauptfenster.keyRechtsDrehen = keyRechtsDrehen;
}
public Hauptfenster(String ip, String port){
//GUI aufrufen
creatGUI();
//Keys erzeugen
keyVor = new Key(87, "W");
keyZurueck = new Key(83, "S");
keyLinks = new Key(65, "A");
keyRechts = new Key(68, "D");
keyLinksDrehen = new Key(81, "Q");
keyRechtsDrehen = new Key(69, "E");
//Verbindung zum Server
verbindung = new Verbindung(ip,Integer.parseInt(port));
addKeyListener(new Tastatursteuerung());
}
publicvoid creatGUI(){
//Fensteroptionen
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(869, 537);
setVisible(true);
setLocationRelativeTo(null);
setFocusable(true);
setTitle("Raspberry Pi Roboter");
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
Kapitel 5: Server und Client | 43
contentPane = new JPanel();
contentPane.setVisible(true);
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(null);
//Buttons
btnVor = new JButton("\r\n");
btnVor.setIcon(new
ImageIcon(Hauptfenster.class.getResource("/PfeileVor.png")));
btnVor.setBounds(547, 68, 88, 57);
btnVor.setFocusable(false);
contentPane.add(btnVor);
btnZurueck = new JButton("");
btnZurueck.setIcon(new
ImageIcon(Hauptfenster.class.getResource("/PfeileZurueck.png")));
btnZurueck.setBounds(547, 135, 88, 57);
btnZurueck.setFocusable(false);
contentPane.add(btnZurueck);
btnRechts = new JButton("");
btnRechts.setIcon(new
ImageIcon(Hauptfenster.class.getResource("/PfeileRechts.png")));
btnRechts.setBounds(641, 68, 88, 57);
btnRechts.setFocusable(false);
contentPane.add(btnRechts);
btnLinks = new JButton("");
btnLinks.setIcon(new
ImageIcon(Hauptfenster.class.getResource("/PfeileLinks.png")));
btnLinks.setBounds(641, 135, 88, 57);
btnLinks.setFocusable(false);
contentPane.add(btnLinks);
btnRechtsDrehen = new JButton("");
btnRechtsDrehen.setIcon(new
ImageIcon(Hauptfenster.class.getResource("/PfeilRechtsDrehen.png")));
btnRechtsDrehen.setBounds(735, 68, 83, 57);
btnRechtsDrehen.setFocusable(false);
contentPane.add(btnRechtsDrehen);
btnLinksDrehen = new JButton("");
btnLinksDrehen.setIcon(new
ImageIcon(Hauptfenster.class.getResource("/PfeilLinksDrehen.png")));
btnLinksDrehen.setBounds(735, 135, 83, 57);
btnLinksDrehen.setFocusable(false);
contentPane.add(btnLinksDrehen);
//Richtungspfeile
gruenerPfeil1 = new JLabel("");
gruenerPfeil1.setIcon(new
ImageIcon(Hauptfenster.class.getResource("/GrünerPfeil.png")));
gruenerPfeil1.setEnabled(false);
gruenerPfeil1.setBounds(543, 235, 52, 82);
contentPane.add(gruenerPfeil1);
gruenerPfeil2 = new JLabel("");
gruenerPfeil2.setIcon(new
ImageIcon(Hauptfenster.class.getResource("/GrünerPfeil.png")));
gruenerPfeil2.setBounds(669, 235, 52, 82);
gruenerPfeil2.setEnabled(false);
contentPane.add(gruenerPfeil2);
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
Kapitel 5: Server und Client | 44
roterPfeil1 = new JLabel("");
roterPfeil1.setBounds(543, 343, 52, 82);
roterPfeil1.setIcon(new
ImageIcon(Hauptfenster.class.getResource("/RoterPfeil.png")));
roterPfeil1.setEnabled(false);
contentPane.add(roterPfeil1);
roterPfeil2 = new JLabel("");
roterPfeil2.setBounds(669, 343, 52, 82);
roterPfeil2.setIcon(new
ImageIcon(Hauptfenster.class.getResource("/RoterPfeil.png")));
roterPfeil2.setEnabled(false);
contentPane.add(roterPfeil2);
lblVersion = new JLabel("Version " + version);
lblVersion.setBounds(750, 11, 68, 14);
contentPane.add(lblVersion);
//Hintergrund
hintergrund = new JLabel("");
hintergrund.setIcon(new
ImageIcon(Hauptfenster.class.getResource("/gui1.png")));
hintergrund.setBounds(0, 0, 854, 476);
contentPane.add(hintergrund);
//MenuBar
menuBar = new JMenuBar();
setJMenuBar(menuBar);
mnDatei = new JMenu("Datei");
menuBar.add(mnDatei);
mntmBeenden = new JMenuItem("Beenden");
mntmBeenden.addActionListener(new Menu());
mnDatei.add(mntmBeenden);
mnOptionen = new JMenu("Optionen");
menuBar.add(mnOptionen);
mntmKeyOptionen = new JMenuItem("Tastenbelegung");
mntmKeyOptionen.addActionListener(new Menu());
mnOptionen.add(mntmKeyOptionen);
mnInfo = new JMenu("Info");
menuBar.add(mnInfo);
mntmCredits = new JMenuItem("Credits");
mntmCredits.addActionListener(new Menu());
mnInfo.add(mntmCredits);
}
//Steuerung des Menu
privateclass Menu implements ActionListener{
publicvoid actionPerformed(ActionEvent e) {
//Menü
if (e.getActionCommand().equals("Beenden")) {
System.exit(1);
}
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
Kapitel 5: Server und Client | 45
if (e.getActionCommand().equals("Tastenbelegung"))
{
new KeyOptionen(keyVor,keyZurueck,
keyLinks,keyRechts,keyLinksDrehen,
keyRechtsDrehen);
}
if (e.getActionCommand().equals("Credits")) {
Object[] options = {"OK"};
JOptionPane.showOptionDialog(null, "Entwickelt
von Andre Mönnich & Eric Ritter", "Credits",
JOptionPane.DEFAULT_OPTION,
JOptionPane.PLAIN_MESSAGE, null, options, options[0]);
}
}
}
privateclass Tastatursteuerung implements KeyListener {
publicvoid keyPressed(KeyEvent e) {
if (e.getKeyCode() == keyVor.getKeycode()) {
btnVor.setBackground(Color.green);
gruenerPfeil1.setEnabled(true);
gruenerPfeil2.setEnabled(true);
verbindung.senden(1);
}
if (e.getKeyCode() == keyZurueck.getKeycode()) {
btnZurueck.setBackground(Color.green);
roterPfeil1.setEnabled(true);
roterPfeil2.setEnabled(true);
verbindung.senden(2);
}
if (e.getKeyCode() == keyLinks.getKeycode()) {
btnLinks.setBackground(Color.green);
gruenerPfeil2.setEnabled(true);
verbindung.senden(3);
}
if (e.getKeyCode() == keyRechts.getKeycode()) {
btnRechts.setBackground(Color.green);
gruenerPfeil1.setEnabled(true);
verbindung.senden(4);
}
if (e.getKeyCode() == keyLinksDrehen.getKeycode())
{
btnLinksDrehen.setBackground(Color.green);
roterPfeil1.setEnabled(true);
gruenerPfeil2.setEnabled(true);
verbindung.senden(5);
}
if (e.getKeyCode() == keyRechtsDrehen.getKeycode())
{
btnRechtsDrehen.setBackground(Color.green);
gruenerPfeil1.setEnabled(true);
roterPfeil2.setEnabled(true);
verbindung.senden(6);
}
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
Kapitel 5: Server und Client | 46
}
publicvoid keyReleased(KeyEvent e) {
if (e.getKeyCode() == keyVor.getKeycode()||
e.getKeyCode() == keyZurueck.getKeycode()||
e.getKeyCode() == keyLinks.getKeycode()||
e.getKeyCode() == keyRechts.getKeycode()||
e.getKeyCode() ==
keyLinksDrehen.getKeycode()||
e.getKeyCode() ==
keyRechtsDrehen.getKeycode()) {
btnVor.setBackground(null);
btnZurueck.setBackground(null);
btnLinks.setBackground(null);
btnRechts.setBackground(null);
btnLinksDrehen.setBackground(null);
btnRechtsDrehen.setBackground(null);
gruenerPfeil1.setEnabled(false);
gruenerPfeil2.setEnabled(false);
roterPfeil1.setEnabled(false);
roterPfeil2.setEnabled(false);
verbindung.senden(0);
}
}
publicvoid keyTyped(KeyEvent e) {
}
}
}
Verbindung:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
publicclass Verbindung{
private Socket verbindung;
private OutputStream out;
private InputStream in;
private PrintWriter writer;
private BufferedReader reader;
privateintnachricht;
/**
* Erstellt einen Socket
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Kapitel 5: Server und Client | 47
* @param ip IP des Socket
* @param port Port des Socket
*/
public Verbindung(String ip, int port){
try {
verbindung = new Socket(ip,port);
System.out.println("Client wurde gestartet!");
//Streams
out = verbindung.getOutputStream();//Zum Senden an
den Client
writer = new PrintWriter(out);
in = verbindung.getInputStream();//Zum Empfangen
vom Server
reader = new BufferedReader(new
InputStreamReader(in));
//----------------------------------------------
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
//SendenThread der Nachrichten an Server sendet
Thread sendenThread = new Thread(){
publicvoid run() {
while (true) {
writer.write(nachricht);
writer.flush();
}
}
};
sendenThread.start();
}
/**
*
* 0 = stopp;
* 1 = vor;
* 2 = zurueck;
* 3 = links;
* 4 = rechts;
* 5 = links-drehen;
* 6 = rechts-drehen;
*
*/
publicvoid senden(int wert){
nachricht = wert;
}
}
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
Kapitel 5: Server und Client | 48
Key:
publicclass Key {
privateintkeycode;
private String keyBezeichnung;
/**
* Einen Key erstellen
* @param keycode Keycode der Taste
* @param keyBezeichnung Keybezeichnung der Taste
*/
public Key(int keycode, String keyBezeichnung){
this.keycode = keycode;
this.keyBezeichnung = keyBezeichnung;
}
publicvoid setKeycode(int newKeyCode){
keycode = newKeyCode;
}
publicint getKeycode(){
returnkeycode;
}
public String getKeyBezeichnung(){
returnkeyBezeichnung;
}
}
KeyOptionen:
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
publicclass KeyOptionen extends JFrame implements ActionListener{
private JPanel contentPane;
private JLabel lblMomentanVor;
private JLabel lblMomentanZurueck;
private JLabel lblMomentanLinks;
private JLabel lblMomentanRechts;
private JLabel lblMomentanLinksDrehen;
private JLabel lblMomentanRechtsDrehen;
private JLabel lblNeueZuweisungen;
private JLabel lblMomentan;
private JLabel lblButtons;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
Kapitel 5: Server und Client | 49
private JLabel lblVor;
private JLabel lblZurueck;
private JLabel lblLinks;
private JLabel lblRechts;
private JLabel lblLinksDrehen;
private JLabel lblRechtsDrehen;
private JButton btnVorNeuZuweisen;
private JButton btnZurueckNeuZuweisen;
private JButton btnLinksNeuZuweisen;
private JButton btnRechtsNeuZuweisen;
private JButton btnLinksDrehenNeuZuweisen;
private JButton btnRechtsDrehenNeuZuweisen;
public KeyOptionen(Key keyVor, Key keyZurueck, Key keyLinks,
Key keyRechts, Key keyLinksDrehen, Key
keyRechtsDrehen){
creatGUI(keyVor,keyZurueck, keyLinks, keyRechts,
keyLinksDrehen, keyRechtsDrehen);
}
publicvoid creatGUI(Key keyVor, Key keyZurueck, Key keyLinks,
Key keyRechts, Key keyLinksDrehen, Key
keyRechtsDrehen){
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
setSize(450, 300);
setLocationRelativeTo(null);
setVisible(true);
setTitle("Tastenbelegung");
setResizable(false);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
btnVorNeuZuweisen = new JButton("Neu zuweisen");
btnVorNeuZuweisen.setBounds(283, 27, 115, 23);
btnVorNeuZuweisen.addActionListener(this);
btnZurueckNeuZuweisen = new JButton("Neu zuweisen");
btnZurueckNeuZuweisen.setBounds(283, 68, 115, 23);
btnZurueckNeuZuweisen.addActionListener(this);
btnLinksNeuZuweisen = new JButton("Neu zuweisen");
btnLinksNeuZuweisen.setBounds(283, 109, 115, 23);
btnLinksNeuZuweisen.addActionListener(this);
btnLinksDrehenNeuZuweisen = new JButton("Neu zuweisen");
btnLinksDrehenNeuZuweisen.setBounds(283, 191, 115, 23);
btnLinksDrehenNeuZuweisen.addActionListener(this);
btnRechtsDrehenNeuZuweisen = new JButton("Neu zuweisen");
btnRechtsDrehenNeuZuweisen.setBounds(283, 232, 115, 23);
btnRechtsDrehenNeuZuweisen.addActionListener(this);
btnRechtsNeuZuweisen = new JButton("Neu zuweisen");
btnRechtsNeuZuweisen.setBounds(283, 150, 115, 23);
btnRechtsNeuZuweisen.addActionListener(this);
lblVor = new JLabel("Vor");
lblVor.setBounds(52, 29, 35, 14);
lblVor.setFont(new Font("Arial", Font.PLAIN, 18));
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
Kapitel 5: Server und Client | 50
lblZurueck = new JLabel("Zur\u00FCck");
lblZurueck.setBounds(32, 70, 55, 14);
lblZurueck.setFont(new Font("Arial", Font.PLAIN, 18));
lblLinks = new JLabel("Links");
lblLinks.setBounds(36, 111, 51, 14);
lblLinks.setFont(new Font("Arial", Font.PLAIN, 18));
lblRechts = new JLabel("Rechts");
lblRechts.setBounds(32, 152, 71, 14);
lblRechts.setFont(new Font("Arial", Font.PLAIN, 18));
lblLinksDrehen = new JLabel("Links Drehen");
lblLinksDrehen.setBounds(14, 193, 115, 14);
lblLinksDrehen.setFont(new Font("Arial", Font.PLAIN,
18));
lblRechtsDrehen = new JLabel("Rechts Drehen");
lblRechtsDrehen.setBounds(10, 234, 129, 14);
lblRechtsDrehen.setFont(new Font("Arial", Font.PLAIN,
18));
lblMomentanVor = new JLabel(keyVor.getKeyBezeichnung());
lblMomentanVor.setFont(new Font("Arial", Font.BOLD, 13));
lblMomentanVor.setHorizontalAlignment(JLabel.CENTER);
lblMomentanVor.setBounds(148, 30, 100, 14);
lblMomentanLinks = new
JLabel(keyLinks.getKeyBezeichnung());
lblMomentanLinks.setFont(new Font("Arial", Font.BOLD,
13));
lblMomentanLinks.setHorizontalAlignment(JLabel.CENTER);
lblMomentanLinks.setBounds(148, 112, 100, 14);
lblMomentanRechts = new
JLabel(keyRechts.getKeyBezeichnung());
lblMomentanRechts.setFont(new Font("Arial", Font.BOLD,
13));
lblMomentanRechts.setHorizontalAlignment(JLabel.CENTER);
lblMomentanRechts.setBounds(148, 153, 100, 14);
lblMomentanLinksDrehen = new
JLabel(keyLinksDrehen.getKeyBezeichnung());
lblMomentanLinksDrehen.setFont(new Font("Arial",
Font.BOLD, 13));
lblMomentanLinksDrehen.setHorizontalAlignment(JLabel.
CENTER);
lblMomentanLinksDrehen.setBounds(148, 194, 100, 14);
lblMomentanRechtsDrehen = new
JLabel(keyRechtsDrehen.getKeyBezeichnung());
lblMomentanRechtsDrehen.setFont(new Font("Arial",
Font.BOLD, 13));
lblMomentanRechtsDrehen.setHorizontalAlignment(JLabel.
CENTER);
lblMomentanRechtsDrehen.setBounds(148, 235, 100, 14);
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
Kapitel 5: Server und Client | 51
lblMomentanZurueck = new
JLabel(keyZurueck.getKeyBezeichnung());
lblMomentanZurueck.setFont(new Font("Arial", Font.BOLD,
13));
lblMomentanZurueck.setHorizontalAlignment(JLabel.CENTER);
lblMomentanZurueck.setBounds(148, 71, 100, 14);
lblNeueZuweisungen = new JLabel("Neue Zuweisungen:");
lblNeueZuweisungen.setBounds(269, 2, 139, 23);
lblNeueZuweisungen.setFont(new Font("Arial", Font.BOLD |
Font.ITALIC, 15));
contentPane.add(lblNeueZuweisungen);
lblMomentan = new JLabel("Momentan:");
lblMomentan.setBounds(159, 2, 89, 23);
lblMomentan.setFont(new Font("Arial", Font.BOLD |
Font.ITALIC, 15));
contentPane.add(lblMomentan);
lblButtons = new JLabel("Buttons:");
lblButtons.setBounds(32, 2, 89, 23);
lblButtons.setFont(new Font("Arial", Font.BOLD |
Font.ITALIC, 15));
contentPane.add(lblButtons);
contentPane.setLayout(null);
contentPane.add(lblVor);
contentPane.add(lblZurueck);
contentPane.add(lblLinks);
contentPane.add(lblRechts);
contentPane.add(lblLinksDrehen);
contentPane.add(lblRechtsDrehen);
contentPane.add(lblMomentanVor);
contentPane.add(lblMomentanZurueck);
contentPane.add(lblMomentanLinks);
contentPane.add(lblMomentanRechts);
contentPane.add(lblMomentanRechtsDrehen);
contentPane.add(lblMomentanLinksDrehen);
contentPane.add(btnVorNeuZuweisen);
contentPane.add(btnZurueckNeuZuweisen);
contentPane.add(btnLinksNeuZuweisen);
contentPane.add(btnRechtsNeuZuweisen);
contentPane.add(btnLinksDrehenNeuZuweisen);
contentPane.add(btnRechtsDrehenNeuZuweisen);
}
publicvoid actionPerformed(ActionEvent e) {
if (e.getSource() == btnVorNeuZuweisen) {
new KeyZuweisung("vor");
}
if (e.getSource() == btnZurueckNeuZuweisen) {
new KeyZuweisung("zurueck");
}
if (e.getSource() == btnLinksNeuZuweisen) {
new KeyZuweisung("links");
}
if (e.getSource() == btnRechtsNeuZuweisen) {
new KeyZuweisung("rechts");
}
if (e.getSource() == btnLinksDrehenNeuZuweisen) {
new KeyZuweisung("linksdrehen");
}
if (e.getSource() == btnRechtsDrehenNeuZuweisen) {
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
Kapitel 5: Server und Client | 52
new KeyZuweisung("rechtsdrehen");
}
}
publicclass KeyZuweisung extends JFrame{
private JPanel contentPane;
public JLabel lblZugewiesen;
private JPanel panel;
private JPanel panel_1;
private JLabel lblBitteZuweisen;
private String gedrueckterButton;
private String [] keyCodeString = new String [222];
Hauptfenster h;
public KeyZuweisung(String button) {
//String Array füllen
keyCodeString();
gedrueckterButton = button;
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
setSize(300, 150);
addKeyListener(new KeyHandler());
setFocusable(true);
setVisible(true);
setTitle("Zuweisung");
setResizable(false);
setLocationRelativeTo(null);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(null);
panel_1 = new JPanel();
panel_1.setBounds(10, 11, 274, 99);
contentPane.add(panel_1);
panel_1.setLayout(null);
lblBitteZuweisen = new JLabel("Auswahl treffen . .
.");
lblBitteZuweisen.setIcon(new
ImageIcon(KeyZuweisung.class.getResource("/RotesKreuz.png")));
lblBitteZuweisen.setFont(new Font("Arial",
Font.BOLD | Font.ITALIC, 24));
lblBitteZuweisen.setBounds(0, 0, 274, 99);
panel_1.add(lblBitteZuweisen);
panel = new JPanel();
panel.setBounds(10, 11, 274, 99);
panel.setVisible(false);
contentPane.add(panel);
panel.setLayout(null);
lblZugewiesen = new JLabel("Zugewiesen . . .");
lblZugewiesen.setBounds(10, 11, 259, 77);
panel.add(lblZugewiesen);
lblZugewiesen.setFont(new Font("Arial", Font.BOLD |
Font.ITALIC, 24));
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
Kapitel 5: Server und Client | 53
lblZugewiesen.setIcon(new
ImageIcon(KeyZuweisung.class.getResource("/Haekchen1.png")));
}
privateclass KeyHandler implements KeyListener{
publicvoid keyPressed(KeyEvent e) {
setFocusable(false);
panel_1.setVisible(false);
panel.setVisible(true);
switch (gedrueckterButton) {
case"vor":
if (keyCodeString[e.getKeyCode()] !=
null) {
Hauptfenster.setKeyVor(new
Key(e.getKeyCode(), keyCodeString[e.getKeyCode()].toUpperCase()));
}else{
Hauptfenster.setKeyVor(new
Key(e.getKeyCode(), String.valueOf(e.getKeyChar()).toUpperCase()));
}
lblMomentanVor.setText(Hauptfenster.getKeyVor().getKeyBezeichnung());
break;
case"zurueck":
if (keyCodeString[e.getKeyCode()] !=
null) {
Hauptfenster.setKeyZurueck(new
Key(e.getKeyCode(), keyCodeString[e.getKeyCode()].toUpperCase()));
}else{
Hauptfenster.setKeyZurueck(new
Key(e.getKeyCode(), String.valueOf(e.getKeyChar()).toUpperCase()));
}
lblMomentanZurueck.setText(Hauptfenster.getKeyZurueck().getKeyBezeich
nung());
break;
case"rechts":
if (keyCodeString[e.getKeyCode()] !=
null) {
Hauptfenster.setKeyRechts(new
Key(e.getKeyCode(), keyCodeString[e.getKeyCode()].toUpperCase()));
}else{
Hauptfenster.setKeyRechts(new
Key(e.getKeyCode(), String.valueOf(e.getKeyChar()).toUpperCase()));
}
lblMomentanRechts.setText(Hauptfenster.getKeyRechts().getKeyBezeichnu
ng());
break;
case"links":
if (keyCodeString[e.getKeyCode()] !=
null) {
Hauptfenster.setKeyLinks(new
Key(e.getKeyCode(), keyCodeString[e.getKeyCode()].toUpperCase()));
}else{
Hauptfenster.setKeyLinks(new
Key(e.getKeyCode(), String.valueOf(e.getKeyChar()).toUpperCase()));
}
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
Kapitel 5: Server und Client | 54
lblMomentanLinks.setText(Hauptfenster.getKeyLinks().getKeyBezeichnung
());
break;
case"rechtsdrehen":
if (keyCodeString[e.getKeyCode()] !=
null) {
Hauptfenster.setKeyRechtsDrehen(new
Key(e.getKeyCode(),
keyCodeString[e.getKeyCode()].toUpperCase()));
}else{
Hauptfenster.setKeyRechtsDrehen(newKey(e.getKeyCode(),
String.valueOf(e.getKeyChar()).toUpperCase()));
}
lblMomentanRechtsDrehen.setText(Hauptfenster.getKeyRechtsDrehen().get
KeyBezeichnung());
break;
case"linksdrehen":
if (keyCodeString[e.getKeyCode()]
!= null) {
Hauptfenster.setKeyLinksDrehen(new
Key(e.getKeyCode(), keyCodeString[e.getKeyCode()].toUpperCase()));
}else{
Hauptfenster.setKeyLinksDrehen(new
Key(e.getKeyCode(), String.valueOf(e.getKeyChar()).toUpperCase()));
}
lblMomentanLinksDrehen.setText(Hauptfenster.getKeyLinksDrehen().getKe
yBezeichnung());
break;
}
}
publicvoid keyTyped(KeyEvent e) {
}
publicvoid keyReleased(KeyEvent e) {
}
}
//KeyCode to String
publicvoid keyCodeString(){
keyCodeString[10]="Enter";
keyCodeString[32]="SPACE";
keyCodeString[17]="STRG";
keyCodeString[16]="Shift";
keyCodeString[37]="Pfeil Links";
keyCodeString[38]="Pfeil Oben";
keyCodeString[39]="Pfeil Rechts";
keyCodeString[40]="Pfeil Unten";
keyCodeString[18]="ALT";
keyCodeString[103]="NUM 7";
keyCodeString[104]="NUM 8";
keyCodeString[105]="NUM 9";
keyCodeString[100]="NUM 4";
keyCodeString[101]="NUM 5";
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
Kapitel 5: Server und Client | 55
Abbildung 5-1: Launcher
Abbildung 5-2: Hauptfenster
keyCodeString[102]="NUM 6";
keyCodeString[97]="NUM 1";
keyCodeString[98]="NUM 2";
keyCodeString[99]="NUM 3";
keyCodeString[96]="NUM 0";
keyCodeString[96]="NUM .";
keyCodeString[107]="NUM +";
keyCodeString[109]="Num -";
keyCodeString[106]="NUM *";
keyCodeString[111]="NUM /";
}
}
}
Beim Programmstart in der Klasse Launcher
wird zunächst der Konstruktor ausgeführt, der
die GUI des Launchers erstellt. Nun muss der
Benutzer den Server auf dem Raspberry Pi
starten und einen Port wählen. Wenn er dies
gemacht hat muss er in die beiden Textfelder
die IP-Adresse des Pis und den eben
gewählten Port eingeben. Nun muss nur noch
auf „Verbinden“ geklickt werden, damit das
eigentliche Programm startet. Im Code ist
hierfür ein ActionListener vorgesehen.
(Launcher Z.: 129-150). Der KeyListener hat in
dieser Klasse nur die Aufgabe, wenn der
Benutzer Enter auf der Tastatur betätigt, dasselbe zu tun, als hätte man mit der Maus auf
den Button Verbinden gedrückt. Bei der Ausführung des ActionListeners wird der Konstruktor
der Klasse „Hauptfenster“ aufgerufen. Dem Konstruktor werden die Einträge in den beiden
Feldern mitgegeben.
Im Konstruktor der Klasse
„Hauptfenster“ wird zunächst die
GUI erstellt. (Hauptfenster Z.: 124).
Danach werden mit der Klasse
„Key“ sechs Tasten für die
Steuerung erzeugt. Dann wird mit
der Klasse „Verbindung“ eine
Verbindung zum Pi hergestellt. Als
letztes wird noch der KeyListener
für die Steuerung, was in der
internen Klasse Tastatursteuerung
abgehalten wird, hinzugefügt.
Springen wir doch zunächst erst mal in den Konstruktor der „Verbindung“-Klasse. Es wird der
String „ip“ und der Integer „port“ übergeben. Mit diesen zwei Parametern wird ein Socket
erstellt. Nun werden noch die Stream zum Übermitteln von Werten zwischen Server und
Client erstellt. Sollte das Verbinden mit dem Server nicht funktionieren läuft das Ganze in
eine Exception. Schließlich wird noch der Thread „sendenThread“ gestartet (Verbindung Z.:
404
405
406
407
408
409
410
411
412
413
414
415
416
417
Kapitel 5: Server und Client | 56
Abbildung 5-3: Taste W wurde gedrückt
Abbildung 5-4: Menüeintrag
Tastenbelegung
65) Dieser Thread sendet durchgehend Integer „nachricht“ an den Server, den der Server
verarbeitet.
Nun schauen wir uns weiter die Klasse „Hauptfenster“ an. Hier gehen wir zur inneren Klasse
„Tastatursteuerung“ (Hauptfenster Z.: 278). Hier werden die Tastatureingaben verarbeitet.
Der KeyListener verlangt drei Methoden, die wir überschreiben. Das sind die Methoden
„keyPressed“, „keyReleased“ und „keyTyped“. Die Methode „keyPressed“ ist dafür zuständig,
was passiert, wenn eine Taste
gedrückt wird. „keyReleased“ sagt
aus, was passiert, wenn ein Button
wieder losgelassen wird und die
Methode wird dann ausgeführt,
wenn auf eine Taste getippt wird.
Wir nutzen in unserem Fall nur die
zwei zuerst genannten Methoden,
da wir mit der Methode „keyTyped“
nichts anfangen können. Widmen
wir uns der „keyPressed“ Methode
zu. Hier finden wir If-Verzweigungen.
Je nachdem welche Taste gedrückt
wird, werden andere Vorgehen verlangt. Wenn zum Beispiel die Taste „W“ drücken, die
momentan für das Vorfahren zuständig ist, wird die erste If-Verzweigung ausgeführt.
(Hauptfenster Z.: 202) Welche Taste gerade für das Vorfahren zuständig ist, bekommt das
Programm aus der Klasse Key mit dem Punktoperator „getKeycode()“.
Zunächst wird der Hintergrund der Button „btnVor“ auf Grün gesetzt, um zu symbolisieren,
dass das Fahrzeug nach Vorne fährt. Dann werden die Pfeile, die den Lauf der Kette
anzeigen sollen, enabled. Da die zwei Pfeile nach vorne grün sind, gehen die Pfeile von grau
(disabled) auf grün (enabled). Am Ende wird an den Server noch die Nachricht „1“, die die
Anweisung Vorfahren symbolisiert, gesendet. Gehen wir kurz zur der dort verwendenden
Methode „senden()“ (Verbindung Z.:80).
In dieser Methode wird der Parameter „wert“ übergeben. Dieser wird dann in den Integer
„nachricht“ abgespeichert. Dieser Integer wird wie oben beschrieben durch den
„sendenThread“ an den Server gesendet. Schauen wir uns nun an, was passiert, wenn die
Taste wieder losgelassen wird. (Hauptfenster Z.:326)
Hier wird abgefragt, ob eine Taste losgelassen wurde. Wenn dies der Fall ist, werden
zunächst die Hintergründe aller Buttons auf „null“ gesetzt. So verlieren alle wieder ihre grüne
Farbe. Danach werden alle Richtungspfeile wieder disabled, damit sie wieder grau sind. Zum
Schluss wird an den Server noch die Nachricht „0“ gesendet, die für das Stoppen steht.
Damit ist alles wieder zurück gesetzt und das Fahrzeug ist im
Stillstand.
Nun müssen wir uns nur noch ansehen, was passiert, wenn
wie in der Menübar den Eintrag Tastenbelegung betätigen.
(Hauptfenster Z.:260)
Hier wird der Konstruktor der Klasse KeyOptionen aufgerufen.
Dabei werden die sechs Key-Objekte „keyVor“, „keyZurueck“,
Kapitel 5: Server und Client | 57
Abbildung 5-5: Tastenbelegung
Abbildung 5-6: Auswahl treffen…
Abbildung 5-7: Zugewiesen…
„keyLinks“, „keyRechts“, „keyLinksDrehen“ und „keyRechtsDrehen“ übergeben. Gehen wir
nun in den Konstruktor (KeyOptionen Z.: 41). Hier wird lediglich die GUI erzeugt. Hierfür
müssen die eben genannten Key-Objekte weitergegeben werden.
Die momentan ausgewählten Tasten bekommt
die Klasse von den Key-Objekten, die
unteranderem einen String „bezeichnung“
besitzen. (z.B. KeyOptionen Z.:123)
Wenn nun auf einen Button „Neu zuweisen“
gedrückt, merkt das der ActionListener und
führt die jeweiligen Befehle aus. Schauen wir
uns hier wieder das Beispiel mit der Taste für
das Vorfahren an. Wenn wir auf den
danebenliegenden Button drücken geht das
Programm in Zeile 199. Hier ruft es den Konstruktor der inneren Klasse KeyZuweisung auf.
(KeyOptionen Z.:262) Es wird übergeben, von welchem Key die Taste umgeändert werden
soll.
Zunächst füllt der Konstruktor das Array
„keyCodeString“. Wofür dieses Array notwendig ist,
erklären wir gleich. Danach wird der Parameter
„button“ in die lokale Variable „gedrueckterButton“
abgespeichert. Darauf folgt das Erzeugen der GUI
„Auswahl treffen…“. Nun wartet das Programm auf
eine Tastatureingabe. Drückt der Benutzer nun eine
Taste, so merkt der KeyListener diesen
Tastendruck (KeyOptionen Z.:293) und setzt den Focus auf false. Damit kann der Benutzer
keine weitere Taste mehr drücken, da für den KeyListener das Fenster fokussiert sein muss.
Danach ändert er die GUI: Er setzt das
„panel_1“(„Auswahl treffen..“) auf unsichtbar und
das „panel“ („Zugewiesen…“) sichtbar.
Nun entscheidet das Programm nach der Variablen
„gedrueckterButton“, welcher Key nun umgeändert
werden muss. Jetzt kommt das Array ins Spiel. Das
Array kennt die Beschreibung des KeyCodes. Wenn
kein String für den KeyCode im Array vorhanden ist,
nutzt das Programm den KeyChar. Das ist notwendig, da manche Tasten, wie z.B. Enter
keinen KeyChar besitzen und dann ein leeres Feld bei den KeyOptionen vorhanden wär.
Mit dem X-Button können die Fenster ganz normal geschlossen werden und der Key ist nun
umgeändert. Man könnte an dieser Stelle das Programm noch so erweitern, dass es selber
merk, dass eine Taste schon für einen Key verwendet wird.
Kapitel 6: Webcam | 58
Kapitel 6
Webcam
Nun wollen wir noch ein Live-Bild vom Roboter haben. Dazu müssen wir zunächst ein
Webcam-Stream auf den Raspberry Pi einrichten und das Live-Bild in unser Programm
einbinden.
Webcamstream-Software installieren Um einen Webcamstream einzurichten benötigen wir zunächst die Software MJPG-
Streamer. Um die auf unserem Raspberry Pi zu installieren, müssen wir zunächst ein Tool
installieren. Das machen wir mit folgendem Befehl:
sudo apt-get install subversion-tools libjep8-dev imagemagick
Wenn dieser Vorgang abgeschlossen ist, können wir nun die erforderlichen Dateien für den
Stream downloaden und installieren.
svn co https://svn.code.sf.net/p/mjpg-streamer/code/
cd code/mjpg-streamer/mjpg-streamer
make
Nun haben wir die Einrichtung des Webcamstreams erfolgreich abgeschlossen.
Webcamstream starten Um den Webcamstream zu starten müssen wir zunächst eine USB-Webcam an den Pi
anschließen. In unserem Fall nutzen wir die im 1.Kaptiel beschriebene Webcam C170 von
Logitech. Dann muss zu dem Ordner mit den MJPG-Dateien navigiert werden. Das wird mit
folgendem Befehl gemacht:
cd code/mjpg-streamer
Anschließend muss der Stream lediglich nur noch gestartet werden. Das geschieht mit
diesem Befehl:
./mjpg_streamer -i "./input_uvc.so -n -y -f 15 -r 489x248" -o
"./output_http.so -n -w ./www -p 8040"
Bei dem Befehl werden dem Stream einige Eigenschaften konfiguriert. Zunächst kann mit
dem Wert hinter „-f“ die Framerate festgelegt. Desweiteren wird hinter „-r“ eine Auflösung der
Aufnahme mitgegeben. Bei dem letzen Wert im Befehl handelt es sich um den Port, auf dem
der Stream läuft.
Kapitel 6: Webcam | 59
Abbildung 6-1: WebcamPanel
Webcampanel Für die nachfolgenden Programme werden zusätzliche Jars benötigt. Diese kann man unter
folgender Adresse im Internet finden:https://github.com/sarxos/webcam-capture 25.05.2014 |
18:00
Ausßerdem benötigen wir noch die slf4j-simple-1.7.6.jar aus dem Verzeichnis, welches man
sich unter folgendem Link herunterladen kann: http://www.slf4j.org/dist/slf4j-1.7.7.zip
(12.06.14 12:29)
Des Weiteren benötigen wir die webcam-capture-driver-ipcam-0.3.10-RC6.jar aus dem
Verzeichnis, das man sich unter folgendem Link herunterladen kann:
http://www.sarxos.pl/repo/maven2/com/github/sarxos/webcam-capture-driver-ipcam/0.3.10-
RC6/webcam-capture-driver-ipcam-0.3.10-RC6-dist.zip (12.06.14 12:29), sowie alle Jars, die
sich in dem Unterverzeichnis lib befinden.
Auch hier müssen wir wieder die Jars zum Buildpath hinzufügen.
Zunächst möchten wir ein einfaches Beispiel zeigen, wie man in Java eine Webcam
einbinden kann.
import javax.swing.JFrame;
import com.github.sarxos.webcam.Webcam;
import com.github.sarxos.webcam.WebcamPanel;
publicclass WebcamPanelExample {
publicstaticvoid main(String[] args) throws
InterruptedException {
//Webcam des Rechners in der Variabelen Webcam speichern
Webcam webcam = Webcam.getDefault();
//Das Webcambild dem WebcamPanbel übergeben
WebcamPanel panel = new WebcamPanel(webcam);
panel.setFPSDisplayed(true);//FPS-Zahl auf dem Panel
JFrame window = new JFrame("Test webcam panel");
window.add(panel);
window.setResizable(false);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.pack();//Dieser Befehl muss aufgerufen werden
window.setVisible(true);
}
}
Der Variablen webcam vom Typ Webcam wird die Kamera
des Rechners zugewiesen. Diese Variablen kann man nun
einem WebcamPanel übergeben. Dies hat die gleichen
Eigenschaften, wie ein „normales“ JPanel, jedoch kann
dieses Panel bewegte Bilder enthalten. Zu erwähnen ist noch,
dass das Fenster mit der Methode „.pack()“ aktualisiert
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
Kapitel 6: Webcam | 60
Abbildung 6-2: Webcamstream im Client
werden muss, ansonsten bleibt das Fenster leer.
Webcam in den Client einbinden Nun müssen wir die Webcam des Pis ansprechen und das Bild auf einem WebcamPanel
einbinden. Dazu haben wir eine neue Klasse WebcamStream geschrieben und das
WebcamPanel in der Hauptfenster-Klasse hinzugefügt. Weitere Erläuterungen finden sich
nach dem Programmcode.
Kapitel 6: Webcam | 61
WebcamStream:
import java.awt.Dimension;
import java.net.MalformedURLException;
import com.github.sarxos.webcam.Webcam;
import com.github.sarxos.webcam.ds.ipcam.IpCamDevice;
import com.github.sarxos.webcam.ds.ipcam.IpCamDriver;
import com.github.sarxos.webcam.ds.ipcam.IpCamMode;
publicclass WebcamStream {
private IpCamDevice ipcam;
private Dimension d;
public WebcamStream(String ip, String port){
try {
ipcam = new IpCamDevice("B7210", "http://" + ip +
":" + port + "/?action=stream",IpCamMode.PUSH);
} catch (MalformedURLException e) {
e.printStackTrace();
}
IpCamDriver driver = new IpCamDriver();
driver.register(ipcam);
Webcam.setDriver(driver);
d = new Dimension(506,255);
}
public Dimension getDimension(){
returnd;
}
}
Hauptfenster:
… … … … … …
… … … … … …
… … … … … …
import com.github.sarxos.webcam.Webcam;
import com.github.sarxos.webcam.WebcamPanel;
publicclass Hauptfenster extends JFrame{
… … … … … …
… … … … … …
… … … … … …
privatestatic WebcamStream stream;
privatestatic WebcamPanel webcamPane;
… … … … … …
… … … … … …
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Kapitel 6: Webcam | 62
… … … … … …
public Hauptfenster(String ip, String port, JCheckBox webcam){
//GUI aufrufen
creatGUI();
//Keys erzeugen
keyVor = new Key(87, "W");
keyZurueck = new Key(83, "S");
keyLinks = new Key(65, "A");
keyRechts = new Key(68, "D");
keyLinksDrehen = new Key(81, "Q");
keyRechtsDrehen = new Key(69, "E");
//Verbindung zum Server
verbindung = new Verbindung(ip,Integer.parseInt(port));
//Webcam
if (webcam.isSelected()) {
try {
createStream(ip, "8040");
} catch (Exception e) {
webcamDurchgestrichen.setVisible(true);
}
}else{
webcamDurchgestrichen.setVisible(true);
}
addKeyListener(new Tastatursteuerung());
}
publicstaticvoid createStream(String ip, String port) {
stream = new WebcamStream(ip, port);
webcamPane = new
WebcamPanel(Webcam.getDefault(),stream.getDimension(),true);
webcamPane.setFillArea(true);
webcamPane.setLayout(null);
webcamPane.setBounds(22,177,489,248);
webcamPane.setVisible(true);
contentPane.add(webcamPane);
}
publicvoid creatGUI(){
… … … … … …
… … … … … …
… … … … … …
webcamDurchgestrichen = new JLabel();
webcamDurchgestrichen.setBounds(90,177,489,248);
webcamDurchgestrichen.setIcon(new
ImageIcon(Hauptfenster.class.getResource
("/WebcamDurchgestrichen.png")));
webcamDurchgestrichen.setVisible(false);
contentPane.add(webcamDurchgestrichen);
… … … … … …
… … … … … …
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
Kapitel 6: Webcam | 63
… … … … … …
}
//Steuerung des Menu
privateclass Menu implements ActionListener{
… … … … … …
… … … … … …
… … … … … …
}
}
Launcher:
… … … … … …
… … … … … …
… … … … … …
import javax.swing.JCheckBox;
publicclass Launcher extends JFrame implements ActionListener,
KeyListener{
… … … … … …
… … … … … …
… … … … … …
private JCheckBox chckbxWebcam;
… … … … … …
… … … … … …
… … … … … …
publicstaticvoid main(String[] args) {
//Launcher aufrufen
… … … … … …
… … … … … …
… … … … … …
}
public Launcher() {
… … … … … …
… … … … … …
… … … … … …
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
Kapitel 6: Webcam | 64
chckbxWebcam = new JCheckBox("");
chckbxWebcam.setBackground(new Color(255,255,255,0));
chckbxWebcam.setBounds(10, 219, 21, 23);
contentPane.add(chckbxWebcam);
… … … … … …
… … … … … …
… … … … … …
}
publicvoid keyPressed(KeyEvent e) {
… … … … … …
}
publicvoid keyTyped(KeyEvent e) {
}
publicvoid keyReleased(KeyEvent e) {
}
publicvoid actionPerformed(ActionEvent e) {
if (e.getSource() == btnVerbinden) {
//Launcher schließen
launcher.dispose();
//GUI starten
EventQueue.invokeLater(new Runnable() {
publicvoid run() {
try {
Hauptfenster frame = new
Hauptfenster(txtIp.getText(),txtPort.getText(), chckbxWebcam);
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
}
Zunächst widmen wir uns der Klasse WebcamStream. Im Konstruktor wird versuchtein
IpCamDevicezu erzeugen. Dieser wird dann inder Variablen „ipcam“ abgespeichert. Hierfür
werden die zwei Parameter „ip“ und „port“ gebraucht, die den URL vervollständigen. Der
URL für den Webcamstream lautet: http://[IP]:[Port]/?action=stream.
Wenn ein IpCamDevice gefunden wurde, wird das Gerät zum IpCamDriver „driver“
hinzugefügt. Der Treiber wird als Standarttreiber für „Webcam“ festgelegt. Mit diesem Treiber
kann man nun das Bild auf das WebcamPanel bringen.
Schauen wir uns hierfür die Klasse Hauptfenster an. Nun wird es erst einmal um die
Methode „createStream“ gehen. (Hauptfenster Z.:58-68) Hier wird der Konstruktor der
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
Kapitel 6: Webcam | 65
Abbildung 6-3: Checkbox
Abbildung 6-4: Webcamstream Abbildung 6-5: durchgestrichene
Webcam
WebcamStream-Klasse aufgerufen, wozu es die Parameter „ip“ und „port“nutzt. Dann wird
dem WebcamPanel „webcamPane“ die Defaultwerte der Webcam, die wir eben geändert
haben, und die Dimensionen, die ebenfalls in der Klasse WebcamStream festgelegt wurden,
übergeben. In den folgenden Zeilen wird noch das Bild auf die Panelgröße skaliert und das
Panel auf der GUI platziert.
Da das Programm immer versucht einen Webcamstream
zu finden, auch wenn es keinen finden kann, kann es sehr
lange dauern, bis die GUI geladen ist. Daher haben wir uns
dazu entschieden auf dem Launcher einfach eine
Checkbox einzubinden, wo der Benutzer entscheiden
kann, ob er einen Stream mit angezeigt haben möchte
oder nicht. Dazu muss die JCheckbox auf dem Launcher
platziert werden und der Status dem Programm übermittelt
werden. Dies passiert in dem Auszug der Launcher-
Klasse. Und je nachdem, für was sich der Benutzer entscheidet, reagiert das Programm.
(Hauptfenster, Z.:44-55) Setzt er kein Hacken in das Kästchen wird eine durchgestrichene
Webcam sichtbar. Wenn er den Hacken setzt erschafft er den Webcamstream. Sollte dies
Fehlschlagen erscheint ebenfalls die durchgestrichene Webcam.
Kapitel 7: Joystick | 66
Abbildung7-1: Koordinatensysteme im Vergleich
Kapitel 7
Joystick
Die Steuerung per Tastatur ist eine praktikable und angenehme Möglichkeit den Roboter zu
steuern. Dennoch wollen wir eine alternative Steuerungsmöglichkeit bieten. Unsere Wahl ist
auf eine Steuerung per Joystick gefallen.
Der Joystick, den wir verwenden ist der Extreme™ 3D Pro von Logitech. Mehr Informationen
darüber befinden sich im 1. Kapitel. Es ist natürlich auch möglich einen anderen Joystick zu
verwenden. Es ist nicht nötig einen Joystick zu verwenden, der ebenfalls so viele Funktionen
hat, wie der Extreme™ 3D Pro. Es ist auch möglich das Programm ohne Joystick
auszuführen. Allerdings muss man dann auf die Steuerung per Joystick verzichten und die
Steuerung per Tastatur oder die Steuerung über die Buttons nutzen.
Die Steuerung erfolgt über die Auslenkung der verschiedenen Achsen. Dabei ist zu
beachten, dass die Achsen des Joysticks nicht mit den Achsen des mathematischen
Koordinatensystems übereinstimmen. Die Y- und Z-Achse des Joysticks sind im Vergleich
zum mathematischen Koordinatensystem vertauscht. Abbildung 7.1 stellt dies nochmal
grafisch dar. Rechts ist das Koordinatensystem des Joysticks zusehen und links das
mathematische Koordinatensystem.
In der Normalstellung liefert die Abfrage der Achsen 0 zurück. Bei maximaler Auslenkung 1
oder -1, je nach der Richtung der Auslenkung.
Damit nicht schon bei der Kleinsten Auslenkung bereits ein Befehl an den Server gesendet
wird richten wir eine „Deadzone“, also eine Toleranzzone, in der Nichts passiert, ein.
Kapitel 7: Joystick | 67
Abbildung 6-1: WebcamPanel
Abbildung 7-2: Aufrufen der Einstellungen
Abbildung 7-3: Festlegen des Native-Pfads
Demnach ergibt sich also folgende Tabelle:
X < 0-deadzone Links
X > 0+deadzone Rechts
Y < 0-deadzone Zurück
Y > 0+deadzone Vor
Z < 0-deadzone Links drehen
Z > 0+deadzone Rechts drehen
Für die Einbindung in unser Programm benutzen wir die jinput-Bibliothek, welche in der
LWJGL-Bibliothek (Lightweight Java Game Library) eingebunden ist. Man kann sie unter
folgendem Link herunterladen: http://sourceforge.net/projects/java-game-
lib/files/Official%20Releases/LWJGL%202.9.1/ 2.6.2014 13:00.
Nach hinzufügen der lwjgl.jar und der jinput.jar zum “Buidpath”, muss man noch die Native –
Dateien zum mit LWJGL verbinden. Dazu öffnet man die Einstellungen von LWJGL indem
man nach einem Rechtsklick auf die lwjgl.jar „Properties“ auswählt (siehe Abbildung 7.2). In
dem sich daraufhin öffnenden Menü (Abbildung 7.3) wählt man dann den Punkt „Native
Library“ aus. Dort wählt man das Verzeichnis der Native-Dateien aus. Die Native Dateien
befinden sich in dem in dem von dem obigen Link gedownloadeten Verzeichnis.
Kapitel 7: Joystick | 68
Kommen wir nun zum Programm: Wir erstellen eine Klasse JoystickController mit dem folgenden Code: import org.lwjgl.LWJGLException;
import org.lwjgl.input.Controller;
import org.lwjgl.input.Controllers;
/**
* Ermöglicht die Steuerung mit Joystick
* Zum starten bitte die Methode start() aufrufen
*
* !!!LWJGL-Native-Pfad muss eingestellt sein!!!
*
* @author Andre
*
*/
publicclass JoystickController {
private Controller controller;
privatefloatdeadzone;
private Verbindung verbindung;
privatebooleanjoystickAktivitaet;
//Getter & Setter
publicvoid setController(int index){
controller = Controllers.getController(index);
}
/**
* Standertkonstruktor index = 0, deadzone = 0.5
*/
public JoystickController(Verbindung client, boolean
joystickAktivitaet){
this.verbindung = client;
this.joystickAktivitaet = joystickAktivitaet;
setDeadzone(0.5f);
try {
Controllers.create();
} catch (LWJGLException e) {
}
controller = Controllers.getController(6);//?
}
/**
*
* @param index (index des gewünschten Controller)
* @param deadzone
*/
public JoystickController(int index, float deadzone, Verbindung
client, boolean joystickAktivitaet){
this.verbindung = client;
this.joystickAktivitaet = joystickAktivitaet;
setDeadzone(deadzone);
try {
Controllers.create();
} catch (LWJGLException e) {
}
controller = Controllers.getController(index);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
Kapitel 7: Joystick | 69
}
/**
* Setzt die Deadzone neu
* @param deadzone
*/
publicvoid setDeadzone(float deadzone){
if (deadzone<=1) {
if (deadzone>=0) {
this.deadzone=deadzone;
}else{
deadzone*=-1;
setDeadzone(deadzone);
}
}else{
deadzone=0.5f;
}
}
/**
* Angeben ob der Joystick aktiv ist
*/
publicvoid setJoystickAktivitaet(boolean aktivitaet){
joystickAktivitaet = aktivitaet;
}
/**
* Erzeugt und startet einen neuen Thread der die Daten des
Joysticks auswertet und entsprechende Befehle an den Server
sendet
*/
publicvoid start(){
Loop loop = new Loop();
loop.setName("JoystickController");
loop.setDaemon(true);
loop.start();
}
privateclass Loop extends Thread{
publicvoid run(){
float x;
float y;
float z;
while (joystickAktivitaet) {
controller.poll();
x=controller.getXAxisValue();
y=controller.getYAxisValue();
z=controller.getRZAxisValue();
if (x>-deadzone&&x<deadzone&& y>-
deadzone&&y<deadzone&& z>-
deadzone&&z<deadzone) {
verbindung.senden(0);//Stopp
}
elseif (x>deadzone){
verbindung.senden(4);//Rechts
}
elseif (x<-deadzone){
verbindung.senden(3);//Links
}
elseif (y>deadzone){
verbindung.senden(2);//Zurueck
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
Kapitel 7: Joystick | 70
}
elseif (y<-deadzone){
verbindung.senden(1);//Vor
}
elseif (z>deadzone){
verbindung.senden(6);//RechtsDrehen
}
elseif (z<-deadzone){//LinksDrehen
verbindung.senden(5);
}
}
Controllers.destroy();
}
}
}
Das Controllerobjekt (Zeile 15) benötigen wir um auf die Methoden, mit denen wir die Achsen
des Joysticks, aufzurufen. Der Konstruktor erwartet einen Index als Parameter. Dieser steht
für das gewünschte Gerät.
Damit die Abfrage der Achsen nicht das ganze Programm blockiert muss das Abfragen
parallel zum Hauptprogramm stattfinden. Dies geschieht durch einen neuen Thread. In der
inneren Klasse Loop wird dieser definiert. Mit der Methode start() wird er gestartet. Der
Thread selbst besteht aus einer Dauerschleife, in der die Achsen abgefragt und ausgewertet
werden und ein entsprechender Befehl zum Server gesendet wird.
Damit die andern Steuerungsmöglichkeiten nicht überdeckt werden soll der soll die
Joysticksteuerung ein- und abschaltbar sein. Dazu fügen wir dem Hauptfenster zwei neue
JButtons hinzu, welche die Joysticksteuerung ein- und ausschalten.
Wenn die Joysticksteuerung gestartet werden soll, wird ein neuer Joystick Controller erzeugt,
und ein neuer Thread gestarted. Soll die Joysticksteuerung beendet werden, wird der
laufende Thread beendet.
Nun haben wir nur noch ein Problem: welchen Index übergeben wir dem Konstruktor? Da
der Benutzer nicht wissen kann welcher Index für welches Gerät steht, müssen wir ihm die
Namen der Geräte zur Auswahl stellen, und daraus dann den Index bestimmen. Damit der
Benutzer jedoch irgendetwas auswählen kann bedarf es einer weiteren Benutzerobberfläche:
Wir programmieren ein neues Fenster Joystickeinstellungen, welches man über die Menübar
auswählen kann.
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import org.lwjgl.input.Controller;
import org.lwjgl.input.Controllers;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JTextField;
import javax.swing.JButton;
publicclassJoystickEinstellungextends JFrame implements
ActionListener{
private JPanel contentPane;
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Kapitel 7: Joystick | 71
privateJComboBoxcomboBoxController;
private Controller controller;
private JLabel lblDeadzone;
private JTextField txtDeadzone;
/**
* Create the frame.
*/
public JoystickEinstellung() {
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
setBounds(100, 100, 429, 156);
setVisible(true);
setResizable(false);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(null);
String[] namen = new
String[Controllers.getControllerCount()];
for (int i = 0; i < namen.length; i++) {
controller = Controllers.getController(i);
namen[i]=controller.getName();
}
comboBoxController = new JComboBox(namen);
comboBoxController.setSelectedIndex(0);
comboBoxController.setBounds(57, 11, 352, 27);
contentPane.add(comboBoxController);
JLabel lblGert = new JLabel("Ger\u00E4t:");
lblGert.setFont(new Font("Tahoma", Font.PLAIN, 14));
lblGert.setBounds(10, 11, 54, 21);
contentPane.add(lblGert);
lblDeadzone = new JLabel("Deadzone:");
lblDeadzone.setFont(new Font("Tahoma", Font.PLAIN, 14));
lblDeadzone.setBounds(10, 54, 79, 21);
contentPane.add(lblDeadzone);
txtDeadzone = new JTextField();
txtDeadzone.setText("0.5");
txtDeadzone.setBounds(80, 56, 33, 20);
contentPane.add(txtDeadzone);
txtDeadzone.setColumns(10);
JButton btnAbbrechen = new JButton("Abbrechen");
btnAbbrechen.setBounds(290, 94, 119, 23);
btnAbbrechen.setActionCommand("Abbrechen");
btnAbbrechen.addActionListener(this);
contentPane.add(btnAbbrechen);
JButton btnOk = new JButton("OK");
btnOk.setBounds(168, 94, 112, 23);
btnOk.setActionCommand("OK");
btnOk.addActionListener(this);
contentPane.add(btnOk);
}
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
78
79
80
81
Kapitel 7: Joystick | 72
publicvoid actionPerformed(ActionEvent e) {
if (e.getActionCommand().equals("Abbrechen")) {
dispose();
}
if (e.getActionCommand().equals("OK")) {
try{
Hauptfenster.setJoystickController(
Float.parseFloat(txtDeadzone.getText()),
comboBoxController.getSelectedIndex());
dispose();
}catch (NumberFormatException exc){
Object[] options = {"OK"};
JOptionPane.showOptionDialog(null, "Ungültige
Zahl", "", JOptionPane.DEFAULT_OPTION,
JOptionPane.PLAIN_MESSAGE, null,
options, options[0] );
}
}
}
}
Das Fenster verfügt über eine JComboBox in der die Namen aller verfügbaren Geräte
angezeigt werden. Den Namen eines Gerätes erhalten wir mit dem Methodenaufruf
getName(). Mit der Methode Controllers.getControllerCount() erhalten wir die
Anzahl der Geräte. So können wir mit einer Schleife die Namen herausfinden (Zeile 38 – 43)
und an die JComboBox übergeben.
Des Weiteren verfügt das Fenster über ein JTextField in dem man einen Wert für die
Deadzone eintragen kann.
Mit einem Klick auf OK wird ein neuer Joystickcontroller erzeugt. Als Index können wir
einfach den ausgewählten Index der JComboBox verwenden, da wir die Reihenfolge ja nicht
verändert haben.
Zu guter Letzt müssen wir in der Klasse Hauptfenster noch eine Variable für ein
JoystickController-Objekt anlegen und eine dazugehöhrige Setter-Methode. Außerdem
müssen wir dem Menü mnOptionen(Hauptfenster Zeile 41) ein weiteres JMenuItem
hinzufügen, mit welchem ein JoystickEinstellungen-Fenster erzeugt wird.
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
Kapitel 8: Ultraschallsensor | 73
Abbildung 8-1: Pins des
Ultraschalsensors
VCC
TRIG ECHO GND
Abbildung 8-2: Zeitdiagramm der Messung
Kapitel 8
Ultraschallsensor
Als kleines Feature bauen wir nun noch einen Ultraschallsensor an den Roboter. Dieser soll
den Freiraum vor dem Roboter messen und an den Client senden.Technische Daten zum
Ultraschallsensor finden sich in Kapitel Nr.1.
Der Sensor besitzt vier Pins: VCC, Trig, Echo und
Ground. VCC ist die Stromzufuhr und wird mit dem
5V-Pin (Pin 2) des Raspberry Pis verbunden. Mit
dem Groundanschluss wir der Sensor geerdet.
Diesen schließen wir natürlich auch an die Ground
(Pin 6) des Raspberry Pins. Den Trig-Pin müssen
wir an einen GPIO-Out Pin anschließen, da hiermit
ein Signal gesendet wird. Der Echo-Pin muss mit
einem GPIO-In Pin verbunden werden, weil dieser
Pin das Signal des Trig empfängt und verarbeitet.
Funktionsweise Auf dem Pin „Trig“ wird ein 10 us langes High-Signal gelegt. Dieser Impuls löst 8 40 kHz Ultraschall Impulse aus.Die gemessene Entfernung ist proportional zur Echo-Puls-Weite am Signal Pin. Wenn die Impulse reflektiert werden misst der Echo die Zeit für das Zurücklegen der Impulese.
Kapitel 8: Ultraschallsensor | 74
Abbildung 8-3: Beispielmessung
Schauen wir uns dem Vorgang an einem Beispiel an. Wir wollen die Entfernung zwischen dem Ultraschallsensor und des Objekts berechnen:
Der Anschluss Nun kommen wir zum anschließen an den Raspberry Pi. Für diesen Anschluss haben wir
uns ein kleines Steckboard zugelegt.
d Objekt Ultraschall-
sensor
Schallgeschwindigkeit:
v = 340 m/s
Formel für das Berechnen der
Geschwindigkeit
Mit der Schallgeschwindigkeit
ergibt sich folgendes: (Gemessen
wird die Schrecke hin und zurück)
Umgestellt:
Abbildung 8-4: Schaltplan
Kapitel 8: Ultraschallsensor | 75
Der Ultraschallsensor wird wie oben im Schema gezeigt an den Raspberry Pi
angeschlossen. Da wir hier mit 5V arbeiten, könnte es den Pin 18 beschädigen. Daher
müssen wir hier durch das Einsetzen von Widerständen die Spannung verringern. Auf der
Steckplatine sieht das Nun folgendermaßen aus:
Python-Programm Nun muss die Messung noch mit einem Programm durchgeführt werden. Wir haben uns mit
Absicht für ein Python-Programm entschieden, da die Zeitmessung bei Java zu ungenau ist.
# Import required Python libraries
import time
import RPi.GPIO as GPIO
# Use BCM GPIO references
# instead of physical pin numbers
GPIO.setmode(GPIO.BCM)
# Define GPIO to use on Pi
GPIO_TRIGGER = 23
GPIO_ECHO = 24
# Set pins as output and input
GPIO.setup(GPIO_TRIGGER,GPIO.OUT) # Trigger
GPIO.setup(GPIO_ECHO,GPIO.IN) # Echo
# Set trigger to False (Low)
GPIO.output(GPIO_TRIGGER, False)
# Allow module to settle
time.sleep(0.5)
# Send 10us pulse to trigger
GPIO.output(GPIO_TRIGGER, True)
time.sleep(0.00001)
GPIO.output(GPIO_TRIGGER, False)
start = time.time()
while GPIO.input(GPIO_ECHO)==0:
start = time.time()
while GPIO.input(GPIO_ECHO)==1:
Abbildung 8-5: Schaltplan auf der Steckplatine
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
Kapitel 8: Ultraschallsensor | 76
stop = time.time()
# Calculate pulse length
elapsed = stop-start
# Distance pulse travelled in that time is time
# multiplied by the speed of sound (cm/s)
distance = elapsed * 17150
print distance
# Reset GPIO settings
GPIO.cleanup()
Zunächst müssen die entsprechenden Libraries
importiert werden. (Zeile 1-3) Danach folgt das
Initialisieren der GPIO-Pins. Hierbei ist zu beachten,
dass bei Python eine andere Pinauswahl vorliegt. Das
bedeutet, dass die GPIO-Pins nicht nach den
Pinnummern vom Raspberry Pi, sondern in unserem
Fall über die GPIO-Bezeichnung angesprochen
werden. Als Trigger wird der GPIO 23 initialisiert und
als Output-Pin festgelegt. Danach folgt der Selbe
Schritt mit dem Echo. Dies wird auf GPIO 24 als Input-
Pin gelegt. Dann wird Trigger noch auf „low“ gesetzt
und eine halbe Sekunde gewartet, damit auch wirklich
alles fertig festgelegt wurde.
Nun beginnt die Messung (Zeile 28), indem auf Trigger
ein 10 µs „High“-Signal gelegt wird. Das Programm
wartet nun so lange, bis das Echo ein „High“-Signal
Empfängt. Ist dies der Fall wird die Zeit genommen
und gewartet, bis das „High“-Signal zu Ende ist. Wenn
das „High“-Signal vorüber ist, wird ein weiteres Mal die Zeit abgespeichert.
Die Zeit errechnet sich aus der Startzeit minus der Endzeit. Die Geschwindigkeit des Schalls
beträgt bei 20° etwa 343 m/s. Da wir das Ganze in cm ausrechnen wollen, rechnen wir auf
34300cm/s um. Dies müssen wir noch durch Zwei teilen, da wir beide Strecken (hin und
zurück) messen aber nur eine haben wollen. Danach wird die Strecke in cm ausgegeben.
In den Client einbinden Wir werden auch beim Einbinden in den Client das eben Vorgestellte Python-Programm
nutzen. Dafür müssen wir unseren Server anpassen und dort das Programm aufrufen und
die Konsolenausgabe auslesen.
ServermitUltraschallsensor (Server):
//Hier darf kein Package genannt werden
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
33
34
35
36
37
38
39
40
41
42
43
44
45
Abbildung 8-6: GPIO-Bezeichnungen
1
2
3
4
5
Kapitel 8: Ultraschallsensor | 77
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Timer;
import java.util.TimerTask;
import Tools.IOTools;
import com.pi4j.io.gpio.GpioController;
import com.pi4j.io.gpio.GpioFactory;
import com.pi4j.io.gpio.GpioPinDigitalOutput;
import com.pi4j.io.gpio.PinState;
import com.pi4j.io.gpio.RaspiPin;
import com.pi4j.system.NetworkInfo;
publicclass ServermitUltraschallsensor {
GpioPinDigitalOutput[] pins = new GpioPinDigitalOutput[4];
BufferedReader reader;
Timer timer;
PrintWriter writer;
publicstaticvoid main(String[] args) throws
InterruptedException{
new ServermitUltraschallsensor();
}
public ServermitUltraschallsensor(){
//GPIO Controller erzeugen
final GpioController gpio = GpioFactory.getInstance();
//Pins dem Array zuweisen und auf low stellen
pins[0] =
gpio.provisionDigitalOutputPin(RaspiPin.GPIO_00, "Motor1Pin2",
PinState.LOW); //Board-Nr=11, links vor
pins[1] =
gpio.provisionDigitalOutputPin(RaspiPin.GPIO_02, "Motor1Pin2",
PinState.LOW); //Board-Nr=13, links zurueck
pins[2] =
gpio.provisionDigitalOutputPin(RaspiPin.GPIO_12, "Motor1Pin2",
PinState.LOW); //Board-Nr=19, rechts zurueck
pins[3] =
gpio.provisionDigitalOutputPin(RaspiPin.GPIO_13, "Motor1Pin2",
PinState.LOW); //Board-Nr=21, rechts vor
try {
System.out.println("Server gestartet . . .");
//Port fuer den Server waehlen
int port = IOTools.readInteger("Bitte waehlen Sie
einen Port: ");
//Server erstellt mit dem Port 5555
ServerSocket host = new ServerSocket(port);
System.out.println("Server gehostet . . .");
for (String ipAddress :
NetworkInfo.getIPAddresses())
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
Kapitel 8: Ultraschallsensor | 78
System.out.println("Der Server ist nun unter
der IP " + ipAddress + " und dem Port " + port
+ " erreichbar . . .");
System.out.println("Warte auf Client . . .");
//Auf Client warten und akzeptieren
Socket client = host.accept();
System.out.println("Client akzeptiert . . .");
//Streams
OutputStream out = client.getOutputStream();//Zum
senden an den Client
writer = new PrintWriter(out);
InputStream in = client.getInputStream();//Zum
Empfangen vom Server
reader = new BufferedReader(new
InputStreamReader(in));
//---------------------------------------
timer = new Timer();
timer.schedule(new
Ultraschallsensor("ultrasonic_1.py"), 0, 500);
} catch (Exception e) {
e.printStackTrace();
}
Thread empfangen = new Thread(){
publicvoid run() {
while (true) {
try {
//InputStream auslesen
switch (reader.read()) {
… … …
… … …
… … …
} catch (IOException e) {
e.printStackTrace();
}
}
};
};
empfangen.start();
}
class Ultraschallsensor extends TimerTask{
Process ultrasonic;
String datei;
public Ultraschallsensor(String datei){
this.datei = datei;
}
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
Kapitel 8: Ultraschallsensor | 79
publicvoid run() {
try {
ultrasonic = Runtime.getRuntime().exec("sudo
python /home/pi/Programme/Ultraschallsensor/" +
datei);
BufferedReader output = new BufferedReader(new
InputStreamReader(ultrasonic.getInputStream()));
String s = null;
s = output.readLine();
double weitetemp = Double.parseDouble(s);
int weite = (int)(Math.round(weitetemp));
writer.write(weite);
writer.flush();
System.out.println(weite);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
Der Server wird wie in Kapitel 5 beschrieben gestartet und eine Verbindung aufgebaut. Auch der Thread zum Empfangen der Nachrichten zur Steuerung sind gleich geblieben. Für uns sind die Zeilen 89-91, sowie die neue innere Klasse „Ultraschallsensor“ interessant. In Zeile 89-91 wird ein neuer Timer erstellt, der die run()-Methode der Klasse „Ultraschallsensor“ alle halbe Sekunde startet, bis das Programm abgebrochen wird. Dabei wird der Dateiname des Python-Programms als Parameter übergeben. Schauen wir uns nun die run()-Methode der Klasse „Ultraschallsensor“ an. (Zeile 132)
Zunächst wird mit Runtime.getRuntime().exec() der Befehl zum Starten des Programms ausgeführt. Danach wird ein BufferedReader angelegt, um die Konsolenausgabe des Programms auszulesen. Da hier die Kommazahl als String ausgelesen wird, muss das Ganze noch in einen double-Wert umgewandelt werden. Um den Wert an den Client zu senden, runden wir den Wert und weißen diesen einer int-Variablen zu. Diese Variable wird nun mit writer.write() an den Client gesendet.
Verbindung (Client):
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
publicclass Verbindung{
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
1
2
3
4
5
6
7
8
9
10
11
Kapitel 8: Ultraschallsensor | 80
private Socket verbindung;
private OutputStream out;
private InputStream in;
private PrintWriter writer;
private BufferedReader reader;
privateintnachricht;
privateintweite;
/**
* Erstellt einen Socket
* @param ip IP des Socket
* @param port Port des Socket
*/
public Verbindung(String ip, int port){
try {
verbindung = new Socket(ip,port);
System.out.println("Client wurde gestartet!");
//Streams
out = verbindung.getOutputStream();//Zum Senden an
den Client
writer = new PrintWriter(out);
in = verbindung.getInputStream();//Zum Empfangen
vom Server
reader = new BufferedReader(new
InputStreamReader(in));
//----------------------------------------------
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
//SendenThread der Nachrichten an Server sendet
Thread sendenThread = new Thread(){
publicvoid run() {
while (true) {
writer.write(nachricht);
writer.flush();
}
}
};
//Vom Server Nachrichten empfangen
Thread empfangenThread = new Thread(){
publicvoid run() {
while (true) {
try {
weite = reader.read();
weite -= 5;//Webcam abziehen
Hauptfenster.setWeiteNachVorne
(weite);
System.out.println(weite);
12
13
14
15
16
17
18
19
20
21
22
23
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
67
68
69
70
71
72
73
74
Kapitel 8: Ultraschallsensor | 81
} catch (IOException e) {
e.printStackTrace();
}
}
}
};
sendenThread.start();
empfangenThread.start();
}
/**
*
* 0 = stopp;
* 1 = vor;
* 2 = zurueck;
* 3 = links;
* 4 = rechts;
* 5 = links-drehen;
* 6 = rechts-drehen;
*
*/
publicvoid senden(int wert){
nachricht = wert;
}
publicint weiteVorne(){
returnweite;
}
}
In der Klasse „Verbindung“ des Clients muss noch ein Thread hinzugefügt werden, damit der
Client auch die Nachrichten des Servers empfängt. Schauen wir uns den Thread
„empfangenThread“ an. Hier wird der Wert mit reader.read() ausgelesen und der int-
Variablen „weite“ zugewiesen. Im Hauptfenster muss nun ein neues JLabel erstellt werden,
welches den Wert ausgibt. Desweiteren wird einer weitere Setter Methode
„setWeiteNachVorne“ hinzugefügt, die den Text des JLabel erneuert. So kann man nun im
Thread die Methode aufrufen und als Parameter die Weite übergeben.
75
76
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
Kapitel 9: Verbesserungen | 82
Kapitel 9
Verbesserungen
In diesem Kapitel stellen wir noch ein paar kleine Verbesserungen an unserem Programm
vor.
Speichern der Einstellungen Wir machen uns die Mühe, dass man das Programm anpassen kann, zu Beispiel, dass man
die Tastenbelegung ändern kann oder die Deadzone des Joysticks festlegen kann. Aber dies
muss man bei jedem Programmstart wiederhohlen - nicht so toll. Deswegen wollen wir die
Einstellungen in einer Datei abspeichern und beim Programmstart die Einstellungen aus
dieser Datei laden.
Dazu erstellen wir eine Klasse Einstellungen.
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
publicclass Einstellungen {
privatestatic String pfad = "einstellungen.txt";
//Keys
privatestatic Key keyVor; //1 beim Senden
privatestatic Key keyZurueck; //2 beim Senden
privatestatic Key keyLinks; //3 beim Senden
privatestatic Key keyRechts; //4 beim Senden
privatestatic Key keyLinksDrehen; //5 beim Senden
privatestatic Key keyRechtsDrehen;//6 beim Senden
//Joystick
privatestatic String controllerName;
privatestaticfloatdeadzone;
/**
* Läd die Einstellungen.
*/
publicstaticvoid laden(){
try {
BufferedReader reader = new BufferedReader(new
FileReader(pfad));
String zeile = reader.readLine();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
Kapitel 9: Verbesserungen | 83
while( !(zeile =
reader.readLine()).equals("ENDE")){
if (zeile.startsWith("keyVor")) {
String inhalt[]=inhalt(zeile);
keyVor = new Key(Integer.parseInt
(inhalt[0]), inhalt[1]);
}
if (zeile.startsWith("keyZurueck")) {
String inhalt[]=inhalt(zeile);
keyZurueck = new Key(Integer.parseInt
(inhalt[0]), inhalt[1]);
}
if (zeile.startsWith("keyLinks")) {
String inhalt[]=inhalt(zeile);
keyLinks = new Key(Integer.parseInt
(inhalt[0]), inhalt[1]);
}
if (zeile.startsWith("keyRechts")) {
String inhalt[]=inhalt(zeile);
keyRechts = new Key(Integer.parseInt
(inhalt[0]), inhalt[1]);
}
if (zeile.startsWith("keyLinksDrehen")) {
String inhalt[]=inhalt(zeile);
keyLinksDrehen = new Key(Integer
.parseInt(inhalt[0]), inhalt[1]);
}
if (zeile.startsWith("keyRechtsDrehen")) {
String inhalt[]=inhalt(zeile);
keyRechtsDrehen = new Key(Integer
.parseInt(inhalt[0]), inhalt[1]);
}
if (zeile.startsWith("controllerName")) {
String[] inhalt = inhalt(zeile);
controllerName = inhalt[0];
}
if (zeile.startsWith("deadzone")) {
String[] inhalt = inhalt(zeile);
deadzone = Float.parseFloat(inhalt[0]);
}
}
reader.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e){
e.printStackTrace();
} catch (ArrayIndexOutOfBoundsException e) {
// TODO: handle exception
}
System.out.println("Einstellungen geladen");
}
/**
* Speichert die Einstellungen.
*/
publicstaticvoid speichern(){
try {
BufferedWriter bw = new BufferedWriter(new
FileWriter(pfad));
bw.write(pfad);
bw.newLine();
bw.newLine();
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
99
Kapitel 9: Verbesserungen | 84
bw.write("ANFANG");
bw.newLine();
bw.write("keyVor = "+keyVor.getKeycode()+",
"+keyVor.getKeyBezeichnung());
bw.newLine();
bw.write("keyZurueck = "+keyZurueck.getKeycode()+",
"+keyZurueck.getKeyBezeichnung());
bw.newLine();
bw.write("keyLinks = "+keyLinks.getKeycode()+",
"+keyLinks.getKeyBezeichnung());
bw.newLine();
bw.write("keyRechts = "+keyRechts.getKeycode()+",
"+keyRechts.getKeyBezeichnung());
bw.newLine();
bw.write("keyLinksDrehen =
"+keyLinksDrehen.getKeycode() +",
"+keyLinksDrehen.getKeyBezeichnung());
bw.newLine();
bw.write("keyRechtsDrehen =
"+keyRechtsDrehen.getKeycode()+",
"+keyRechtsDrehen.getKeyBezeichnung());
bw.newLine();
bw.write("controllerName = " + controllerName);
bw.newLine();
bw.write("deadzone = " + deadzone);
bw.newLine();
bw.write("ENDE");
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* Setzt die Einstellungen auf die Standertwerte zurück.
*/
publicstaticvoid zuruecksetzen(){
try {
BufferedWriter bw = new BufferedWriter(new
FileWriter("einstellungen.txt"));
bw.write("einstellungen.txt");
bw.newLine();
bw.newLine();
bw.write("ANFANG");
bw.newLine();
bw.write("keyVor = 87, W");
bw.newLine();
bw.write("keyZurueck = 83, S");
bw.newLine();
bw.write("keyLinks = 65, A");
bw.newLine();
bw.write("keyRechts = 68, D");
bw.newLine();
bw.write("keyLinksDrehen = 81, Q");
bw.newLine();
bw.write("keyRechtsDrehen = 69, E");
bw.newLine();
bw.write("controlleName = null");
bw.newLine();
bw.write("deadzone = 0.5");
bw.write("ENDE");
bw.close();
} catch (IOException e) {
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
Kapitel 9: Verbesserungen | 85
e.printStackTrace();
}
pfad = "einstellungen.txt";
laden();
}
/**
* Setzt den Pfad der Datei die beim Laden und Speichern
* verwendet wird auf das Argument.
* @param pfad
*/
publicstaticvoid setPfad(String pfad){
Einstellungen.pfad = pfad;
}
//Getter und Setter
//Einstellungen
//Keys
publicstaticvoid setKeyVor(Key newKey){
keyVor = newKey;
}
publicstatic Key getKeyVor(){
returnkeyVor;
}
publicstatic Key getKeyZurueck() {
returnkeyZurueck;
}
publicstaticvoid setKeyZurueck(Key keyZurueck) {
keyZurueck = keyZurueck;
}
publicstatic Key getKeyLinks() {
returnkeyLinks;
}
publicstaticvoid setKeyLinks(Key keyLinks) {
keyLinks = keyLinks;
}
publicstatic Key getKeyRechts() {
returnkeyRechts;
}
publicstaticvoid setKeyRechts(Key keyRechts) {
keyRechts = keyRechts;
}
publicstatic Key getKeyLinksDrehen() {
returnkeyLinksDrehen;
}
publicstaticvoid setKeyLinksDrehen(Key keyLinksDrehen) {
keyLinksDrehen = keyLinksDrehen;
}
publicstatic Key getKeyRechtsDrehen() {
returnkeyRechtsDrehen;
}
publicstaticvoid setKeyRechtsDrehen(Key keyRechtsDrehen) {
keyRechtsDrehen = keyRechtsDrehen;
}
publicstatic String getControllerName() {
returncontrollerName;
}
publicstaticfloat getDeadzone() {
returndeadzone;
}
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
Kapitel 9: Verbesserungen | 86
publicstaticvoid setControllerName(String controllerName) {
Einstellungen.controllerName = controllerName;
}
publicstaticvoid setDeadzone(float f) {
Einstellungen.deadzone = f;
}
privatestatic String[] inhalt(String zeile){
String inhalt = zeile.split("=", 2)[1];
inhalt = inhalt.replace(" ", "");
return inhalt.split(",");
}
}
Außerdem erzeugen wir eine Textdatei, die folgendermaßen aussieht:
einstellungen.txt
ANFANG
keyVor = 87, W
keyZurueck = 83, S
keyLinks = 81, Q
keyRechts = 69, E
keyLinksDrehen = 81, Q
keyRechtsDrehen = 69, E
controllerName = Logitech Extrem 3D
deadzone = 0.5
ENDE
Doch nun zur Erklärung der Klasse. Als erstes fügen wir alle Variablen die gespeichert
werden sollen (Zeile 12-22). Da wir sie auf private gesezt haben müssen wir auch die Getter
und Setter einfügen (Zeile 184-232). Natürlich müssen wir nun an allen Stellen an denen die
Variablen aufgerufen werden die Getter-Methoden verwenden. Des Weiteren haben wir eine
Variable in der der Pfad der Datei angegeben ist.
Die die Methoden laden(), speichern() und zuruecksetzen() bilden den Kern der Klasse.
Mit der Methode laden() laden wir die Einstellungen aus einer Datei. Dazu nutzen wir einen
BufferedReader (Zeile 29-30). Indem wir auf das BufferedReader-Objekt (in unserem Fall
reader) die Methode readLine() aufrufen erhalten wir einen String mit der ersten Zeile der
Datei. Rufen wir die Methode ein zweites Mal auf erhalten wir zweite Zeile der Datei. Rufen
wir die Methode nochmal auf erhalten wir die nächste Zeile. In unserem Programm rufen wir
die Methode solange auf, wie in der Zeile nicht ENDE steht (Zeile 37, 38). Nach dem wir die
Zeile augerufen haben überprüfen wir um welche Variable es sich bei der Zeile handelt.
Dazu benutzen wir die Methode startsWidth() der Klasse String (Zeile .39, 44, 49, 54, 59, 64,
69 und 73). Nach dem wir herrausgefunden haben welcher Variable wir die Zeile zuordenen
sollen müssen wir jetzt den Wert der Variable herrausfinden. Dazu rufen wir unsere Methode
inhalt() auf (Zeile 234 -239). Diese liefert uns ein String-Array zurück mit den einzelnen
Werten der Variable. Danach weisen wir der Variable den Wert zu. Im Fall der Keys rufen wir
den Konstruktor auf und übergeben die Werte. Zu beachten ist jedoch dass die
nummerischen Werte noch als String gespeichert sind und noch in einen nummerischen
Wert mit Hilfe der Methoden parseInt() der Klasse Integer bzw. parseFloat der Klasse Float
umgewandelt werden müssen. Da bei Dateien immer Fehler auftreten können müssen wir
mögliche Fehler abfagen. Zum schluss rufen wir noch die Methode close() auf unseren
reader auf um den Lesevorgang zu beenden.
226
227
228
229
230
231
232
233
234
235
236
237
238
239
1
2
3
4
5
6
7
8
9
10
11
12
Kapitel 9: Verbesserungen | 87
Mit der Methode speichern() können wir die Werte der Variablen verwunderlicher Weise
abspeichern. Dazu benutzen wir einen BufferedWriter (94-95). Mit der Method write() können
wir einen übergebenen String in eine Datei schreiben. Mit der Methode newLine() erzeugen
wir eine neue Zeile. In die Datei Schreiben wir müssen wir nun nurnoch den Namen der
Variablen und den Wert hineinschreiben. Damit sich die Datei als Mensch besser lesen lässt
fügen wir noch ein = Zeichen zwischen den Namen und dem Wert ein. Zeile 96 – 126. Hier
müssen wir zum Schluss noch die Methode close() auf unseren BufferedeWriter aufrufen,
damit der Schreibvorgang beendet wird und die Datei gespeichert wird.
Die Methode zuruecksetzen() macht im Grunde nichts anderes, als die Methode
speicheren(). Jedoch wird hier nicht der aktuelle Wert der Variable abgespeichert, sondern
ein von uns Vordefinierter. Damit dies auch sofort wirkt, wird nach dem zurücksetzen der
Datei die Methode laden aufgerufen.
Eine Besonderheit stellt der controller für den Joystick dar. Wir können nicht den Index
verwenden, da sich dieser beim nächsten Programmstart verändert haben könnte.
Deswegen speichern wir den Namen der Joysticks ab und überprüfen beim nächsten
erzeugen des controllers, ob es ein Gerät gibt, das den abgespeicherten Namen trägt.
Damit die Einstellungen auch beim Programmstart geladen werden, müssen wir ledeglich die
Methode laden() aufrufen. Wir rufen die Methode im Konstruktor des Haupfensters auf. Da
alles in der Klasse statisch ist müssen wir vorher kein Objekt erzeugen. Wir können sie
einfach mit Einstellungen.laden(); aufrufen. Damit eine Änderung auch beim nächsten
Programmstart wirksam ist rufen wir nach jeder Änderung die Methode speichern auf. Die
Methode zuruecksetzen() lässt sich über die Menübar aufrufen.
: Fazit | 88
Fazit
Zum Vollenden unser Umfangreichen Dokumentation wollen wir noch ein kurzes Fazit
geben.
Wir haben uns mit dem Legoroboter ein großartiges, aber auch sehr umfangreiches Thema
ausgesucht. Die Entwicklung des Legoroboters hat uns viel Freude bereitet und hat gezeigt,
dass der Informatikzweig der ARS genau das Richtige für uns ist.
Wir haben in den Legoroboter viel Zeit und Engagement investiert, wobei auch nicht alles
beim ersten Mal funktioniert hat. Die Mühe hat sich dennoch gelohnt. Wir haben das Projekt
mit großem Erfolg abgeschlossen und sind mit dem Ergebnis weitaus zufrieden.
Bei dem Projektarbeiten eigneten wir uns viel neues Wissen an und hatten viel Gelegenheit
unser vorhandenes Wissen einzusetzen. Schon allein deswegen können wir das Projekt als
einen Erfolg ansehen. Wir hoffen, dass wir einen Teil dieses Wissens mit dieser
Dokumentation weitergeben können.
Mit dem Raspberry Pi werden wir uns auch in Zukunft noch beschäftigen, denn die
Möglichkeiten sind mit unserem Legoroboter längst nicht ausgereizt. Leider ist das Projekt so
schnell vergangen. Wir hätten noch viele weitere Dinge, wie z.B. eine APP entwickeln
können.
: Anhang | 89
Anhang
Das gesamte Programm Launcher: import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.ImageIcon;
import javax.swing.JTextField;
import javax.swing.JLabel;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JButton;
import java.awt.Color;
import javax.swing.JCheckBox;
publicclass Launcher extends JFrame implements ActionListener, KeyListener{
private JPanel contentPane;
private JButton btnVerbinden;
private JTextField txtIp;
private JTextField txtPort;
private JCheckBox chckbxWebcam;
private JLabel lblHintergrundLauncher;
private JLabel lblIpadresse;
private JLabel lblPort;
private JLabel lblWebcam;
privatestatic Launcher launcher;
publicstaticvoid main(String[] args) {
//Launcher aufrufen
EventQueue.invokeLater(new Runnable() {
publicvoid run() {
try {
launcher = new Launcher();
launcher.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
: Anhang | 90
}
});
}
public Launcher() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 450, 328);
setLocationRelativeTo(null);
setResizable(false);
setTitle("Launcher");
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(null);
txtIp = new JTextField();
txtIp.setBounds(10, 268, 197, 20);
contentPane.add(txtIp);
txtIp.addKeyListener(this);
txtIp.setColumns(10);
txtPort = new JTextField();
txtPort.setBounds(217, 268, 113, 20);
contentPane.add(txtPort);
txtPort.addKeyListener(this);
txtPort.setColumns(10);
chckbxWebcam = new JCheckBox("");
chckbxWebcam.setBackground(new Color(255,255,255,0));
chckbxWebcam.setBounds(10, 219, 21, 23);
contentPane.add(chckbxWebcam);
lblWebcam = new JLabel("Webcam");
lblWebcam.setForeground(Color.WHITE);
lblWebcam.setBounds(32, 224, 56, 14);
contentPane.add(lblWebcam);
lblIpadresse = new JLabel("IP-Adresse");
lblIpadresse.setForeground(Color.WHITE);
lblIpadresse.setBounds(10, 249, 197, 14);
contentPane.add(lblIpadresse);
lblPort = new JLabel("Port");
lblPort.setForeground(Color.WHITE);
lblPort.setBounds(217, 249, 46, 14);
contentPane.add(lblPort);
btnVerbinden = new JButton("Verbinden");
btnVerbinden.setBounds(335, 265, 99, 23);
btnVerbinden.addActionListener(this);
contentPane.add(btnVerbinden);
lblHintergrundLauncher = new JLabel();
lblHintergrundLauncher.setBounds(0, 0, 450, 300);
lblHintergrundLauncher.setIcon(new
ImageIcon(Hauptfenster.class.getResource("/HintergrundLauncher.png"))
);
contentPane.add(lblHintergrundLauncher);
}
: Anhang | 91
publicvoid keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ENTER){
btnVerbinden.doClick();
}
}
publicvoid keyTyped(KeyEvent e) {
}
publicvoid keyReleased(KeyEvent e) {
}
publicvoid actionPerformed(ActionEvent e) {
if (e.getSource() == btnVerbinden) {
//Launcher schließen
launcher.dispose();
//GUI starten
EventQueue.invokeLater(new Runnable() {
publicvoid run() {
try {
Hauptfenster frame = new
Hauptfenster(txtIp.getText(),txtPort.getText(),
chckbxWebcam);
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
}
Hauptfenster: import java.awt.Color;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import com.github.sarxos.webcam.Webcam;
: Anhang | 92
import com.github.sarxos.webcam.WebcamPanel;
publicclass Hauptfenster extends JFrame{
finaldoubleversion = 5.0;
privatestatic JPanel contentPane;
private JButton btnVor;
private JButton btnZurueck;
private JButton btnLinks;
private JButton btnRechts;
private JButton btnLinksDrehen;
private JButton btnRechtsDrehen;
private JButton btnJoystickAn;
private JButton btnJoystickAus;
private JLabel hintergrund;
private JLabel roterPfeil1;
private JLabel roterPfeil2;
private JLabel gruenerPfeil1;
private JLabel gruenerPfeil2;
private JLabel lblJoystick;
private JLabel webcamDurchgestrichen;
private JLabel lblVersion;
private JLabel lblWeiteNachVorne;
privatestatic JLabel lblWeiteNachVorne2;
private JMenuBar menuBar;
private JMenu mnDatei;
private JMenu mnOptionen;
private JMenu mnInfo;
private JMenuItem mntmBeenden;
private JMenuItem mntmKeyOptionen;
private JMenuItem mntmJoystick;
private JMenuItem mntmEinstellungenZuruecksetzen;
private JMenuItem mntmCredits;
privatestatic JoystickController joystickController;
privatestatic WebcamStream stream;
privatestatic WebcamPanel webcamPane;
private Verbindung verbindung;
//Getter & Setter
publicstaticvoid setWeiteNachVorne(int weite){
lblWeiteNachVorne2.setText(weite + " cm");
}
publicstaticvoid setJoystickController(float deadzone, int
controllerIndex)
{
joystickController.setDeadzone(deadzone);
}
public Hauptfenster(String ip, String port, JCheckBox webcam){
: Anhang | 93
//Einstellungen laden
Einstellungen.laden();
//GUI aufrufen
creatGUI();
//Verbindung zum Server
verbindung = new Verbindung(ip,Integer.parseInt(port));
//Webcam
if (webcam.isSelected()) {
try {
createStream(ip, "8040");
} catch (Exception e) {
webcamDurchgestrichen.setVisible(true);
}
}else{
webcamDurchgestrichen.setVisible(true);
}
addKeyListener(new Tastatursteuerung());
joystickController = new JoystickController(verbindung, false);
}
publicstaticvoid createStream(String ip, String port) {
stream = new WebcamStream(ip, port);
webcamPane = new
WebcamPanel(Webcam.getDefault(),stream.getDimension(),true);
webcamPane.setFillArea(true);
webcamPane.setLayout(null);
webcamPane.setBounds(22,177,489,248);
webcamPane.setVisible(true);
contentPane.add(webcamPane);
}
publicvoid creatGUI(){
//Fensteroptionen
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(869, 537);
setVisible(true);
setLocationRelativeTo(null);
setFocusable(true);
setTitle("Raspberry Pi Roboter");
contentPane = new JPanel();
contentPane.setVisible(true);
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(null);
webcamDurchgestrichen = new JLabel();
webcamDurchgestrichen.setBounds(90,177,489,248);
webcamDurchgestrichen.setIcon(new
ImageIcon(Hauptfenster.class.getResource
("/WebcamDurchgestrichen.png")));
webcamDurchgestrichen.setVisible(false);
contentPane.add(webcamDurchgestrichen);
//Buttons
btnVor = new JButton("\r\n");
btnVor.setIcon(newImageIcon(Hauptfenster.class.
getResource("/PfeileVor.png")));
: Anhang | 94
btnVor.setBounds(547, 68, 88, 57);
btnVor.setFocusable(false);
contentPane.add(btnVor);
btnZurueck = new JButton("");
btnZurueck.setIcon(new
ImageIcon(Hauptfenster.class.getResource("/PfeileZurueck.png")));
btnZurueck.setBounds(547, 135, 88, 57);
btnZurueck.setFocusable(false);
contentPane.add(btnZurueck);
btnRechts = new JButton("");
btnRechts.setIcon(new
ImageIcon(Hauptfenster.class.getResource("/PfeileRechts.png")));
btnRechts.setBounds(641, 68, 88, 57);
btnRechts.setFocusable(false);
contentPane.add(btnRechts);
btnLinks = new JButton("");
btnLinks.setIcon(new
ImageIcon(Hauptfenster.class.getResource("/PfeileLinks.png")));
btnLinks.setBounds(641, 135, 88, 57);
btnLinks.setFocusable(false);
contentPane.add(btnLinks);
btnRechtsDrehen = new JButton("");
btnRechtsDrehen.setIcon(new
ImageIcon(Hauptfenster.class.getResource("/PfeilRechtsDrehen.png")));
btnRechtsDrehen.setBounds(735, 68, 83, 57);
btnRechtsDrehen.setFocusable(false);
contentPane.add(btnRechtsDrehen);
btnLinksDrehen = new JButton("");
btnLinksDrehen.setIcon(new
ImageIcon(Hauptfenster.class.getResource("/PfeilLinksDrehen.png")));
btnLinksDrehen.setBounds(735, 135, 83, 57);
btnLinksDrehen.setFocusable(false);
contentPane.add(btnLinksDrehen);
//Richtungspfeile
gruenerPfeil1 = new JLabel("");
gruenerPfeil1.setIcon(new
ImageIcon(Hauptfenster.class.getResource("/GrünerPfeil.png")));
gruenerPfeil1.setEnabled(false);
gruenerPfeil1.setBounds(543, 235, 52, 82);
contentPane.add(gruenerPfeil1);
gruenerPfeil2 = new JLabel("");
gruenerPfeil2.setIcon(new
ImageIcon(Hauptfenster.class.getResource("/GrünerPfeil.png")));
gruenerPfeil2.setBounds(669, 235, 52, 82);
gruenerPfeil2.setEnabled(false);
contentPane.add(gruenerPfeil2);
roterPfeil1 = new JLabel("");
roterPfeil1.setBounds(543, 343, 52, 82);
: Anhang | 95
roterPfeil1.setIcon(new
ImageIcon(Hauptfenster.class.getResource("/RoterPfeil.png")));
roterPfeil1.setEnabled(false);
contentPane.add(roterPfeil1);
roterPfeil2 = new JLabel("");
roterPfeil2.setBounds(669, 343, 52, 82);
roterPfeil2.setIcon(new
ImageIcon(Hauptfenster.class.getResource("/RoterPfeil.png")));
roterPfeil2.setEnabled(false);
contentPane.add(roterPfeil2);
//Joystickoptionen
lblJoystick = new JLabel("Joysticksteuerung");
lblJoystick.setBounds(193, 64, 110, 18);
contentPane.add(lblJoystick);
btnJoystickAn = new JButton("An");
btnJoystickAn.setFocusable(false);
btnJoystickAn.setBounds(313, 64, 60, 18);
btnJoystickAn.setActionCommand("tglbtnAn");
btnJoystickAn.addActionListener(new Menu());
contentPane.add(btnJoystickAn);
btnJoystickAus = new JButton("Aus");
btnJoystickAus.setFocusable(false);
btnJoystickAus.setBounds(370, 64, 68, 18);
btnJoystickAus.setBackground(Color.red);
btnJoystickAus.setActionCommand("tglbtnAus");
btnJoystickAus.addActionListener(new Menu());
contentPane.add(btnJoystickAus);
lblVersion = new JLabel("Version " + version);
lblVersion.setBounds(750, 11, 68, 14);
contentPane.add(lblVersion);
lblWeiteNachVorne = new JLabel("Weite nach Vorne");
lblWeiteNachVorne.setBounds(193, 104, 127, 14);
contentPane.add(lblWeiteNachVorne);
lblWeiteNachVorne2 = new JLabel("---");
lblWeiteNachVorne2.setFont(new Font("Tahoma", Font.BOLD, 11));
lblWeiteNachVorne2.setBounds(330, 104, 46, 14);
contentPane.add(lblWeiteNachVorne2);
//Hintergrund
hintergrund = new JLabel("");
hintergrund.setIcon(new
ImageIcon(Hauptfenster.class.getResource("/gui1.png")));
hintergrund.setBounds(0, 0, 854, 476);
contentPane.add(hintergrund);
//MenuBar
menuBar = new JMenuBar();
setJMenuBar(menuBar);
mnDatei = new JMenu("Datei");
menuBar.add(mnDatei);
mntmBeenden = new JMenuItem("Beenden");
mntmBeenden.addActionListener(new Menu());
mnDatei.add(mntmBeenden);
: Anhang | 96
mnOptionen = new JMenu("Optionen");
menuBar.add(mnOptionen);
mntmKeyOptionen = new JMenuItem("Tastenbelegung");
mntmKeyOptionen.addActionListener(new Menu());
mnOptionen.add(mntmKeyOptionen);
mntmJoystick = new JMenuItem("Joystick & co");
mntmJoystick.setActionCommand("Joystick");
mntmJoystick.addActionListener(new Menu());
mnOptionen.add(mntmJoystick);
mntmEinstellungenZuruecksetzen = new JMenuItem("Einstellungen
zurücksetzen");
mntmEinstellungenZuruecksetzen.setActionCommand("EinstellungenZurueck
setzen");
mntmEinstellungenZuruecksetzen.addActionListener(new Menu());
mnOptionen.add(mntmEinstellungenZuruecksetzen);
mnInfo = new JMenu("Info");
menuBar.add(mnInfo);
mntmCredits = new JMenuItem("Credits");
mntmCredits.addActionListener(new Menu());
mnInfo.add(mntmCredits);
}
//Steuerung des Menu
privateclass Menu implements ActionListener{
publicvoid actionPerformed(ActionEvent e) {
//Menü
if (e.getActionCommand().equals("Beenden")) {
joystickController.setJoystickAktivitaet(false);
System.exit(1);
}
if (e.getActionCommand().equals("Tastenbelegung")) {
new KeyOptionen();
}
if (e.getActionCommand().equals("Joystick")){
new JoystickEinstellung();
}
if (e.getActionCommand().equals("Credits")) {
Object[] options = {"OK"};
JOptionPane.showOptionDialog(null, "Entwickelt von
Andre Mönnich & Eric Ritter", "Credits",
JOptionPane.DEFAULT_OPTION,JOptionPane.PLAIN_MESSAGE, null,
options, options[0]);
}
if (e.getSource() == mntmEinstellungenZuruecksetzen) {
Einstellungen.zuruecksetzen();
}
//Togglebuttons
: Anhang | 97
If(e.getActionCommand().equals(btnJoystickAn.
getActionCommand())) {
joystickController.setJoystickAktivitaet(true);
joystickController.start();
btnJoystickAn.setSelected(true);
btnJoystickAus.setSelected(false);
btnJoystickAn.setBackground(Color.GREEN);
btnJoystickAus.setBackground(new
Color(240,240,240));
}
if
(e.getActionCommand().equals(btnJoystickAus.getActionCommand())) {
joystickController.setJoystickAktivitaet(false);
btnJoystickAus.setSelected(true);
btnJoystickAn.setSelected(false);
btnJoystickAus.setBackground(Color.red);
btnJoystickAn.setBackground(new
Color(240,240,240));
}
}
}
privateclass Tastatursteuerung implements KeyListener {
publicvoid keyPressed(KeyEvent e) {
if (e.getKeyCode() ==
Einstellungen.getKeyVor().getKeycode()) {
btnVor.setBackground(Color.green);
gruenerPfeil1.setEnabled(true);
gruenerPfeil2.setEnabled(true);
verbindung.senden(1);
}
if (e.getKeyCode() ==
Einstellungen.getKeyZurueck().getKeycode()) {
btnZurueck.setBackground(Color.green);
roterPfeil1.setEnabled(true);
roterPfeil2.setEnabled(true);
verbindung.senden(2);
}
if (e.getKeyCode() ==
Einstellungen.getKeyLinks().getKeycode()) {
btnLinks.setBackground(Color.green);
gruenerPfeil2.setEnabled(true);
verbindung.senden(3);
}
if (e.getKeyCode() ==
Einstellungen.getKeyRechts().getKeycode()) {
btnRechts.setBackground(Color.green);
gruenerPfeil1.setEnabled(true);
verbindung.senden(4);
}
if (e.getKeyCode() ==
Einstellungen.getKeyLinksDrehen().getKeycode()) {
btnLinksDrehen.setBackground(Color.green);
roterPfeil1.setEnabled(true);
gruenerPfeil2.setEnabled(true);
verbindung.senden(5);
: Anhang | 98
}
if (e.getKeyCode() ==
Einstellungen.getKeyRechtsDrehen().getKeycode()) {
btnRechtsDrehen.setBackground(Color.green);
gruenerPfeil1.setEnabled(true);
roterPfeil2.setEnabled(true);
verbindung.senden(6);
}
}
publicvoid keyReleased(KeyEvent e) {
if (e.getKeyCode() ==
Einstellungen.getKeyVor().getKeycode()||
e.getKeyCode() ==
Einstellungen.getKeyZurueck().getKeycode()||
e.getKeyCode() ==
Einstellungen.getKeyLinks().getKeycode()||
e.getKeyCode() ==
Einstellungen.getKeyRechts().getKeycode()||
e.getKeyCode() ==
Einstellungen.getKeyLinksDrehen().getKeycode()||
e.getKeyCode() ==
Einstellungen.getKeyRechtsDrehen().getKeycode()) {
btnVor.setBackground(null);
btnZurueck.setBackground(null);
btnLinks.setBackground(null);
btnRechts.setBackground(null);
btnLinksDrehen.setBackground(null);
btnRechtsDrehen.setBackground(null);
gruenerPfeil1.setEnabled(false);
gruenerPfeil2.setEnabled(false);
roterPfeil1.setEnabled(false);
roterPfeil2.setEnabled(false);
verbindung.senden(0);
}
}
publicvoid keyTyped(KeyEvent e) {
}
}
}
Verbindung: import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
: Anhang | 99
import java.net.UnknownHostException;
publicclass Verbindung{
private Socket verbindung;
private OutputStream out;
private InputStream in;
private PrintWriter writer;
private BufferedReader reader;
privateintnachricht;
privateintweite;
/**
* Erstellt einen Socket
* @param ip IP des Socket
* @param port Port des Socket
*/
public Verbindung(String ip, int port){
try {
verbindung = new Socket(ip,port);
System.out.println("Client wurde gestartet!");
//Streams
out = verbindung.getOutputStream();//Zum Senden an den
Client
writer = new PrintWriter(out);
in = verbindung.getInputStream();//Zum Empfangen vom
Server
reader = new BufferedReader(new InputStreamReader(in));
//----------------------------------------------
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
//SendenThread der Nachrichten an Server sendet
Thread sendenThread = new Thread(){
publicvoid run() {
while (true) {
writer.write(nachricht);
writer.flush();
}
}
};
//Vom Server Nachrichten empfangen
Thread empfangenThread = new Thread(){
publicvoid run() {
: Anhang | 100
while (true) {
try {
weite = reader.read();
weite -= 5;//Webcam abziehen
Hauptfenster.setWeiteNachVorne(weite);
System.out.println(weite);
} catch (IOException e) {
e.printStackTrace();
}
}
}
};
sendenThread.start();
empfangenThread.start();
}
/**
*
* 0 = stopp;
* 1 = vor;
* 2 = zurueck;
* 3 = links;
* 4 = rechts;
* 5 = links-drehen;
* 6 = rechts-drehen;
*
*/
publicvoid senden(int wert){
nachricht = wert;
}
publicint weiteVorne(){
returnweite;
}
}
Einstellungen: import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
publicclass Einstellungen {
privatestatic String pfad = "einstellungen.txt";
//Keys
privatestatic Key keyVor; //1 beim Senden
privatestatic Key keyZurueck; //2 beim Senden
privatestatic Key keyLinks; //3 beim Senden
privatestatic Key keyRechts; //4 beim Senden
privatestatic Key keyLinksDrehen; //5 beim Senden
privatestatic Key keyRechtsDrehen;//6 beim Senden
//Joystick
privatestatic String controllerName;
privatestaticfloatdeadzone;
/**
* Läd die Einstellungen.
: Anhang | 101
*/
publicstaticvoid laden(){
try {
BufferedReader reader = new BufferedReader(new
FileReader(pfad));
String zeile = reader.readLine();
if (!zeile.equals("einstellungen.txt")) {
pfad = zeile;
laden();
return;
}
while( !(zeile = reader.readLine()).equals("ENDE")){
if (zeile.startsWith("keyVor")) {
String inhalt[]=inhalt(zeile);
keyVor = new Key(Integer.parseInt(inhalt[0]),
inhalt[1]);
}
if (zeile.startsWith("keyZurueck")) {
String inhalt[]=inhalt(zeile);
keyZurueck = new
Key(Integer.parseInt(inhalt[0]), inhalt[1]);
}
if (zeile.startsWith("keyLinks")) {
String inhalt[]=inhalt(zeile);
keyLinks = new
Key(Integer.parseInt(inhalt[0]),
inhalt[1]);
}
if (zeile.startsWith("keyRechts")) {
String inhalt[]=inhalt(zeile);
keyRechts = new
Key(Integer.parseInt(inhalt[0]),inhalt[1]);
}
if (zeile.startsWith("keyLinksDrehen")) {
String inhalt[]=inhalt(zeile);
keyLinksDrehen = new
Key(Integer.parseInt(inhalt[0]),
inhalt[1]);
}
if (zeile.startsWith("keyRechtsDrehen")) {
String inhalt[]=inhalt(zeile);
keyRechtsDrehen = new
Key(Integer.parseInt(inhalt[0]),
inhalt[1]);
}
if (zeile.startsWith("controllerName")) {
String[] inhalt = inhalt(zeile);
controllerName = inhalt[0];
}
if (zeile.startsWith("deadzone")) {
String[] inhalt = inhalt(zeile);
deadzone = Float.parseFloat(inhalt[0]);
}
}
reader.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e){
e.printStackTrace();
} catch (ArrayIndexOutOfBoundsException e) {
// TODO: handle exception
}
System.out.println("Einstellungen geladen");
: Anhang | 102
}
/**
* Speichert die Einstellungen.
*/
publicstaticvoid speichern(){
try {
BufferedWriter bw = new BufferedWriter(new
FileWriter(pfad));
bw.write(pfad);
bw.newLine();
bw.newLine();
bw.write("ANFANG");
bw.newLine();
bw.write("keyVor = "+keyVor.getKeycode()+",
"+keyVor.getKeyBezeichnung());
bw.newLine();
bw.write("keyZurueck = "+keyZurueck.getKeycode()+",
"+keyZurueck.getKeyBezeichnung());
bw.newLine();
bw.write("keyLinks = "+keyLinks.getKeycode()+",
"+keyLinks.getKeyBezeichnung());
bw.newLine();
bw.write("keyRechts = "+keyRechts.getKeycode()+",
"+keyRechts.getKeyBezeichnung());
bw.newLine();
bw.write("keyLinksDrehen =
"+keyLinksDrehen.getKeycode()+",
"+keyLinksDrehen.getKeyBezeichnung());
bw.newLine();
bw.write("keyRechtsDrehen =
"+keyRechtsDrehen.getKeycode()+",
"+keyRechtsDrehen.getKeyBezeichnung());
bw.newLine();
bw.write("controllerName = " + controllerName);
bw.newLine();
bw.write("deadzone = " + deadzone);
bw.newLine();
bw.write("ENDE");
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* Setzt die Einstellungen auf die Standertwerte zurück.
*/
publicstaticvoid zuruecksetzen(){
try {
BufferedWriter bw = new BufferedWriter(new
FileWriter("einstellungen.txt"));
bw.write("einstellungen.txt");
bw.newLine();
bw.newLine();
bw.write("ANFANG");
bw.newLine();
: Anhang | 103
bw.write("keyVor = 87, W");
bw.newLine();
bw.write("keyZurueck = 83, S");
bw.newLine();
bw.write("keyLinks = 65, A");
bw.newLine();
bw.write("keyRechts = 68, D");
bw.newLine();
bw.write("keyLinksDrehen = 81, Q");
bw.newLine();
bw.write("keyRechtsDrehen = 69, E");
bw.newLine();
bw.write("controlleName = null");
bw.newLine();
bw.write("deadzone = 0.5");
bw.write("ENDE");
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
pfad = "einstellungen.txt";
laden();
}
/**
* Setzt den Pfad der Datei die beim Laden und Speichern verwendet
wird auf das Argument.
* @param pfad
*/
publicstaticvoid setPfad(String pfad){
Einstellungen.pfad = pfad;
}
//Getter und Setter
//Einstellungen
//Keys
publicstaticvoid setKeyVor(Key newKey){
keyVor = newKey;
}
publicstatic Key getKeyVor(){
returnkeyVor;
}
publicstatic Key getKeyZurueck() {
returnkeyZurueck;
}
publicstaticvoid setKeyZurueck(Key keyZurueck) {
keyZurueck = keyZurueck;
}
publicstatic Key getKeyLinks() {
returnkeyLinks;
}
publicstaticvoid setKeyLinks(Key keyLinks) {
keyLinks = keyLinks;
}
publicstatic Key getKeyRechts() {
returnkeyRechts;
}
publicstaticvoid setKeyRechts(Key keyRechts) {
keyRechts = keyRechts;
}
publicstatic Key getKeyLinksDrehen() {
returnkeyLinksDrehen;
}
: Anhang | 104
publicstaticvoid setKeyLinksDrehen(Key keyLinksDrehen) {
keyLinksDrehen = keyLinksDrehen;
}
publicstatic Key getKeyRechtsDrehen() {
returnkeyRechtsDrehen;
}
publicstaticvoid setKeyRechtsDrehen(Key keyRechtsDrehen) {
keyRechtsDrehen = keyRechtsDrehen;
}
publicstatic String getControllerName() {
returncontrollerName;
}
publicstaticfloat getDeadzone() {
returndeadzone;
}
publicstaticvoid setControllerName(String controllerName) {
Einstellungen.controllerName = controllerName;
}
publicstaticvoid setDeadzone(float f) {
Einstellungen.deadzone = f;
}
privatestatic String[] inhalt(String zeile){
String inhalt = zeile.split("=", 2)[1];
inhalt = inhalt.replace(" ", "");
return inhalt.split(",");
}
}
Key: publicclass Key {
privateintkeycode;
private String keyBezeichnung;
/**
* Einen Key erstellen
* @param keycode Keycode der Taste
* @param keyBezeichnung Keybezeichnung der Taste
*/
public Key(int keycode, String keyBezeichnung){
this.keycode = keycode;
this.keyBezeichnung = keyBezeichnung;
}
publicvoid setKeycode(int newKeyCode){
keycode = newKeyCode;
}
publicint getKeycode(){
returnkeycode;
}
public String getKeyBezeichnung(){
returnkeyBezeichnung;
}
}
: Anhang | 105
KeyOptionen: import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
publicclass KeyOptionen extends JFrame implements ActionListener{
private JPanel contentPane;
private JLabel lblMomentanVor;
private JLabel lblMomentanZurueck;
private JLabel lblMomentanLinks;
private JLabel lblMomentanRechts;
private JLabel lblMomentanLinksDrehen;
private JLabel lblMomentanRechtsDrehen;
private JLabel lblNeueZuweisungen;
private JLabel lblMomentan;
private JLabel lblButtons;
private JLabel lblVor;
private JLabel lblZurueck;
private JLabel lblLinks;
private JLabel lblRechts;
private JLabel lblLinksDrehen;
private JLabel lblRechtsDrehen;
private JButton btnVorNeuZuweisen;
private JButton btnZurueckNeuZuweisen;
private JButton btnLinksNeuZuweisen;
private JButton btnRechtsNeuZuweisen;
private JButton btnLinksDrehenNeuZuweisen;
private JButton btnRechtsDrehenNeuZuweisen;
public KeyOptionen(){
creatGUI();
}
publicvoid creatGUI(){
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
setSize(450, 300);
setLocationRelativeTo(null);
setVisible(true);
setTitle("Tastenbelegung");
setResizable(false);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
btnVorNeuZuweisen = new JButton("Neu zuweisen");
btnVorNeuZuweisen.setBounds(283, 27, 115, 23);
btnVorNeuZuweisen.addActionListener(this);
: Anhang | 106
btnZurueckNeuZuweisen = new JButton("Neu zuweisen");
btnZurueckNeuZuweisen.setBounds(283, 68, 115, 23);
btnZurueckNeuZuweisen.addActionListener(this);
btnLinksNeuZuweisen = new JButton("Neu zuweisen");
btnLinksNeuZuweisen.setBounds(283, 109, 115, 23);
btnLinksNeuZuweisen.addActionListener(this);
btnLinksDrehenNeuZuweisen = new JButton("Neu zuweisen");
btnLinksDrehenNeuZuweisen.setBounds(283, 191, 115, 23);
btnLinksDrehenNeuZuweisen.addActionListener(this);
btnRechtsDrehenNeuZuweisen = new JButton("Neu zuweisen");
btnRechtsDrehenNeuZuweisen.setBounds(283, 232, 115, 23);
btnRechtsDrehenNeuZuweisen.addActionListener(this);
btnRechtsNeuZuweisen = new JButton("Neu zuweisen");
btnRechtsNeuZuweisen.setBounds(283, 150, 115, 23);
btnRechtsNeuZuweisen.addActionListener(this);
lblVor = new JLabel("Vor");
lblVor.setBounds(52, 29, 35, 14);
lblVor.setFont(new Font("Arial", Font.PLAIN, 18));
lblZurueck = new JLabel("Zur\u00FCck");
lblZurueck.setBounds(32, 70, 55, 14);
lblZurueck.setFont(new Font("Arial", Font.PLAIN, 18));
lblLinks = new JLabel("Links");
lblLinks.setBounds(36, 111, 51, 14);
lblLinks.setFont(new Font("Arial", Font.PLAIN, 18));
lblRechts = new JLabel("Rechts");
lblRechts.setBounds(32, 152, 71, 14);
lblRechts.setFont(new Font("Arial", Font.PLAIN, 18));
lblLinksDrehen = new JLabel("Links Drehen");
lblLinksDrehen.setBounds(14, 193, 115, 14);
lblLinksDrehen.setFont(new Font("Arial", Font.PLAIN, 18));
lblRechtsDrehen = new JLabel("Rechts Drehen");
lblRechtsDrehen.setBounds(10, 234, 129, 14);
lblRechtsDrehen.setFont(new Font("Arial", Font.PLAIN, 18));
lblMomentanVor = new
JLabel(Einstellungen.getKeyVor().getKeyBezeichnung());
lblMomentanVor.setFont(new Font("Arial", Font.BOLD, 13));
lblMomentanVor.setHorizontalAlignment(JLabel.CENTER);
lblMomentanVor.setBounds(148, 30, 100, 14);
lblMomentanLinks = new
JLabel(Einstellungen.getKeyLinks().getKeyBezeichnung());
lblMomentanLinks.setFont(new Font("Arial", Font.BOLD, 13));
lblMomentanLinks.setHorizontalAlignment(JLabel.CENTER);
lblMomentanLinks.setBounds(148, 112, 100, 14);
lblMomentanRechts = new
JLabel(Einstellungen.getKeyRechts().getKeyBezeichnung());
lblMomentanRechts.setFont(new Font("Arial", Font.BOLD, 13));
lblMomentanRechts.setHorizontalAlignment(JLabel.CENTER);
lblMomentanRechts.setBounds(148, 153, 100, 14);
: Anhang | 107
lblMomentanLinksDrehen = new
JLabel(Einstellungen.getKeyLinksDrehen().getKeyBezeichnung());
lblMomentanLinksDrehen.setFont(new Font("Arial", Font.BOLD,
13));
lblMomentanLinksDrehen.setHorizontalAlignment(JLabel.CENTER);
lblMomentanLinksDrehen.setBounds(148, 194, 100, 14);
lblMomentanRechtsDrehen = new
JLabel(Einstellungen.getKeyRechtsDrehen().getKeyBezeichnung());
lblMomentanRechtsDrehen.setFont(new Font("Arial", Font.BOLD,
13));
lblMomentanRechtsDrehen.setHorizontalAlignment(JLabel.CENTER);
lblMomentanRechtsDrehen.setBounds(148, 235, 100, 14);
lblMomentanZurueck = new
JLabel(Einstellungen.getKeyZurueck().getKeyBezeichnung());
lblMomentanZurueck.setFont(new Font("Arial", Font.BOLD, 13));
lblMomentanZurueck.setHorizontalAlignment(JLabel.CENTER);
lblMomentanZurueck.setBounds(148, 71, 100, 14);
lblNeueZuweisungen = new JLabel("Neue Zuweisungen:");
lblNeueZuweisungen.setBounds(269, 2, 139, 23);
lblNeueZuweisungen.setFont(new Font("Arial", Font.BOLD |
Font.ITALIC, 15));
contentPane.add(lblNeueZuweisungen);
lblMomentan = new JLabel("Momentan:");
lblMomentan.setBounds(159, 2, 89, 23);
lblMomentan.setFont(new Font("Arial", Font.BOLD | Font.ITALIC,
15));
contentPane.add(lblMomentan);
lblButtons = new JLabel("Buttons:");
lblButtons.setBounds(32, 2, 89, 23);
lblButtons.setFont(new Font("Arial", Font.BOLD | Font.ITALIC,
15));
contentPane.add(lblButtons);
contentPane.setLayout(null);
contentPane.add(lblVor);
contentPane.add(lblZurueck);
contentPane.add(lblLinks);
contentPane.add(lblRechts);
contentPane.add(lblLinksDrehen);
contentPane.add(lblRechtsDrehen);
contentPane.add(lblMomentanVor);
contentPane.add(lblMomentanZurueck);
contentPane.add(lblMomentanLinks);
contentPane.add(lblMomentanRechts);
contentPane.add(lblMomentanRechtsDrehen);
contentPane.add(lblMomentanLinksDrehen);
contentPane.add(btnVorNeuZuweisen);
contentPane.add(btnZurueckNeuZuweisen);
contentPane.add(btnLinksNeuZuweisen);
contentPane.add(btnRechtsNeuZuweisen);
contentPane.add(btnLinksDrehenNeuZuweisen);
contentPane.add(btnRechtsDrehenNeuZuweisen);
}
: Anhang | 108
publicvoid actionPerformed(ActionEvent e) {
if (e.getSource() == btnVorNeuZuweisen) {
new KeyZuweisung("vor");
}
if (e.getSource() == btnZurueckNeuZuweisen) {
new KeyZuweisung("zurueck");
}
if (e.getSource() == btnLinksNeuZuweisen) {
new KeyZuweisung("links");
}
if (e.getSource() == btnRechtsNeuZuweisen) {
new KeyZuweisung("rechts");
}
if (e.getSource() == btnLinksDrehenNeuZuweisen) {
new KeyZuweisung("linksdrehen");
}
if (e.getSource() == btnRechtsDrehenNeuZuweisen) {
new KeyZuweisung("rechtsdrehen");
}
}
publicclass KeyZuweisung extends JFrame{
private JPanel contentPane;
public JLabel lblZugewiesen;
private JPanel panel;
private JPanel panel_1;
private JLabel lblBitteZuweisen;
private String gedrueckterButton;
private String [] keyCodeString = new String [222];
Hauptfenster h;
public KeyZuweisung(String button) {
//String Array füllen
keyCodeString();
gedrueckterButton = button;
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
setSize(300, 150);
addKeyListener(new KeyHandler());
setFocusable(true);
setVisible(true);
setTitle("Zuweisung");
setResizable(false);
setLocationRelativeTo(null);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(null);
panel_1 = new JPanel();
panel_1.setBounds(10, 11, 274, 99);
contentPane.add(panel_1);
panel_1.setLayout(null);
lblBitteZuweisen = new JLabel("Auswahl treffen . . .");
: Anhang | 109
lblBitteZuweisen.setIcon(new
ImageIcon(KeyZuweisung.class.getResource("/RotesKreuz.png")));
lblBitteZuweisen.setFont(new Font("Arial", Font.BOLD |
Font.ITALIC, 24));
lblBitteZuweisen.setBounds(0, 0, 274, 99);
panel_1.add(lblBitteZuweisen);
panel = new JPanel();
panel.setBounds(10, 11, 274, 99);
panel.setVisible(false);
contentPane.add(panel);
panel.setLayout(null);
lblZugewiesen = new JLabel("Zugewiesen . . .");
lblZugewiesen.setBounds(10, 11, 259, 77);
panel.add(lblZugewiesen);
lblZugewiesen.setFont(new Font("Arial", Font.BOLD |
Font.ITALIC, 24));
lblZugewiesen.setIcon(new
ImageIcon(KeyZuweisung.class.getResource("/Haekchen1.png")));
}
privateclass KeyHandler implements KeyListener{
publicvoid keyPressed(KeyEvent e) {
setFocusable(false);
panel_1.setVisible(false);
panel.setVisible(true);
switch (gedrueckterButton) {
case"vor":
if (keyCodeString[e.getKeyCode()] != null) {
Einstellungen.setKeyVor(new
Key(e.getKeyCode(), keyCodeString[e.getKeyCode()].toUpperCase()));
}else{
Einstellungen.setKeyVor(new
Key(e.getKeyCode(), String.valueOf(e.getKeyChar()).toUpperCase()));
}
lblMomentanVor.setText(Einstellungen.getKeyVor().getKeyBezeichnung())
;
break;
case"zurueck":
if (keyCodeString[e.getKeyCode()] != null) {
Einstellungen.setKeyZurueck(new
Key(e.getKeyCode(),
keyCodeString[e.getKeyCode()].toUpperCase()));
}else{
Einstellungen.setKeyZurueck(new
Key(e.getKeyCode(),
String.valueOf(e.getKeyChar()).toUpperCase()));
}
lblMomentanZurueck.setText(Einstellungen.getKeyZurueck().getKeyBezeic
hnung());
break;
case"rechts":
if (keyCodeString[e.getKeyCode()] != null) {
: Anhang | 110
Einstellungen.setKeyRechts(new
Key(e.getKeyCode(), keyCodeString[e.getKeyCode()].toUpperCase()));
}else{
Einstellungen.setKeyRechts(new
Key(e.getKeyCode(), String.valueOf(e.getKeyChar()).toUpperCase()));
}
lblMomentanRechts.setText(Einstellungen.getKeyRechts().getKeyBezeichn
ung ());
break;
case"links":
if (keyCodeString[e.getKeyCode()] != null) {
Einstellungen.setKeyLinks(new
Key(e.getKeyCode(), keyCodeString[e.getKeyCode()].toUpperCase()));
}else{
Einstellungen.setKeyLinks(new
Key(e.getKeyCode(), String.valueOf(e.getKeyChar()).toUpperCase()));
}
lblMomentanLinks.setText(Einstellungen.getKeyLinks().getKeyBezeichnun
g());
break;
case"rechtsdrehen":
if (keyCodeString[e.getKeyCode()] != null) {
Einstellungen.setKeyRechtsDrehen(new
Key(e.getKeyCode(),
keyCodeString[e.getKeyCode()].toUpperCase()));
}else{
Einstellungen.setKeyRechtsDrehen(new
Key(e.getKeyCode(), String.valueOf(e.getKeyChar()).toUpperCase()));
}
lblMomentanRechtsDrehen.setText(Einstellungen.getKeyRechtsDrehen().ge
tKeyBezeichnung());
break;
case"linksdrehen":
if (keyCodeString[e.getKeyCode()] != null) {
Einstellungen.setKeyLinksDrehen(new
Key(e.getKeyCode(), keyCodeString[e.getKeyCode()].toUpperCase()));
}else{
Einstellungen.setKeyLinksDrehen(new
Key(e.getKeyCode(), String.valueOf(e.getKeyChar()).toUpperCase()));
}
lblMomentanLinksDrehen.setText(Einstellungen.getKeyLinksDrehen().getK
eyBezeichnung());
break;
}
System.out.println("KeyChar: " + e.getKeyChar());
System.out.println("KeyCode: " + e.getKeyCode());
Einstellungen.speichern();
}
publicvoid keyTyped(KeyEvent e) {
}
@Override
publicvoid keyReleased(KeyEvent e) {
: Anhang | 111
}
}
//KeyCode to String
publicvoid keyCodeString(){
keyCodeString[10]="Enter";
keyCodeString[32]="SPACE";
keyCodeString[17]="STRG";
keyCodeString[16]="Shift";
keyCodeString[37]="Pfeil Links";
keyCodeString[38]="Pfeil Oben";
keyCodeString[39]="Pfeil Rechts";
keyCodeString[40]="Pfeil Unten";
keyCodeString[18]="ALT";
keyCodeString[103]="NUM 7";
keyCodeString[104]="NUM 8";
keyCodeString[105]="NUM 9";
keyCodeString[100]="NUM 4";
keyCodeString[101]="NUM 5";
keyCodeString[102]="NUM 6";
keyCodeString[97]="NUM 1";
keyCodeString[98]="NUM 2";
keyCodeString[99]="NUM 3";
keyCodeString[96]="NUM 0";
keyCodeString[96]="NUM .";
keyCodeString[107]="NUM +";
keyCodeString[109]="Num -";
keyCodeString[106]="NUM *";
keyCodeString[111]="NUM /";
}
}
}
WebcamStream: import java.awt.Dimension;
import java.net.MalformedURLException;
import com.github.sarxos.webcam.Webcam;
import com.github.sarxos.webcam.ds.ipcam.IpCamDevice;
import com.github.sarxos.webcam.ds.ipcam.IpCamDriver;
import com.github.sarxos.webcam.ds.ipcam.IpCamMode;
publicclass WebcamStream {
private IpCamDevice ipcam;
private Dimension d;
public WebcamStream(String ip, String port){
try {
ipcam = new IpCamDevice("B7210", "http://" + ip + ":" +
port +"/?action=stream",IpCamMode.PUSH);
} catch (MalformedURLException e) {
e.printStackTrace();
}
IpCamDriver driver = new IpCamDriver();
driver.register(ipcam);
Webcam.setDriver(driver);
d = new Dimension(506,255);
}
: Anhang | 112
public Dimension getDimension(){
returnd;
}
}
JoystickController: import org.lwjgl.LWJGLException;
import org.lwjgl.input.Controller;
import org.lwjgl.input.Controllers;
/**
* Ermöglicht die Steuerung mit Joystick
* Zum starten bitte die Methode start() aufrufen
*
*/
public class JoystickController {
private Controller controller;
private float deadzone;
private Verbindung verbindung;
private boolean joystickAktivitaet;
//Getter & Setter
public void setController(int index){
controller = Controllers.getController(index);
}
/**
* Standertkonstruktor index = 0, deadzone = 0.5
*/
public JoystickController(Verbindung client, boolean
joystickAktivitaet){
this.verbindung = client;
this.joystickAktivitaet = joystickAktivitaet;
setDeadzone(0.5f);
try {
Controllers.create();
} catch (LWJGLException e) {
}
controller = Controllers.getController(1);//?
}
/**
*
* @param index (index des gewünschten Controller)
* @param deadzone
*/
public JoystickController(int index, float deadzone, Verbindung
client, boolean joystickAktivitaet){
this.verbindung = client;
this.joystickAktivitaet = joystickAktivitaet;
setDeadzone(deadzone);
try {
Controllers.create();
} catch (LWJGLException e) {
}
controller = Controllers.getController(index);
: Anhang | 113
}
/**
* Setzt die Deadzone neu
* @param deadzone
*/
public void setDeadzone(float deadzone){
if (deadzone<=1) {
if (deadzone>=0) {
this.deadzone=deadzone;
}else{
deadzone*=-1;
setDeadzone(deadzone);
}
}else{
deadzone=0.5f;
}
}
/**
* Angeben ob der Joystick aktiv ist
*/
public void setJoystickAktivitaet(boolean aktivitaet){
joystickAktivitaet = aktivitaet;
}
/**
* Erzeugt und startet einen neuen Thread der die Daten des Joysticks
auswertet und entsprechende Befehle an den Server sendet
*/
public void start(){
Loop loop = new Loop();
loop.setName("JoystickController");
loop.setDaemon(true);
loop.start();
}
private class Loop extends Thread{
public void run(){
float x;
float y;
float z;
while (joystickAktivitaet) {
controller.poll();
x=controller.getXAxisValue();
y=controller.getYAxisValue();
z=controller.getRZAxisValue();
if (x>-deadzone&&x<deadzone && y>-
deadzone&&y<deadzone && z>-deadzone&&z<deadzone) {
verbindung.senden(0);//Stopp
}
else if (x>deadzone){
verbindung.senden(4);//Rechts
}
else if (x<-deadzone){
verbindung.senden(3);//Links
}
else if (y>deadzone){
verbindung.senden(2);//Zurueck
}
else if (y<-deadzone){
: Anhang | 114
verbindung.senden(1);//Vor
}
else if (z>deadzone){
verbindung.senden(6);//RechtsDrehen
}
else if (z<-deadzone){//LinksDrehen
verbindung.senden(5);
}
}
Controllers.destroy();
}
}
}
JoystickEinstellungen: import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import org.lwjgl.input.Controller;
import org.lwjgl.input.Controllers;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JTextField;
import javax.swing.JButton;
publicclass JoystickEinstellung extends JFrame implements
ActionListener{
private JPanel contentPane;
private JComboBox comboBoxController;
private Controller controller;
private JLabel lblDeadzone;
private JTextField txtDeadzone;
/**
* Create the frame.
*/
public JoystickEinstellung() {
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
setBounds(100, 100, 429, 156);
setVisible(true);
setResizable(false);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(null);
String[] namen = new
String[Controllers.getControllerCount()];
for (int i = 0; i < namen.length; i++) {
controller = Controllers.getController(i);
namen[i]=controller.getName();
: Anhang | 115
}
comboBoxController = new JComboBox(namen);
comboBoxController.setSelectedIndex(0);
comboBoxController.setBounds(57, 11, 352, 27);
contentPane.add(comboBoxController);
JLabel lblGert = new JLabel("Ger\u00E4t:");
lblGert.setFont(new Font("Tahoma", Font.PLAIN, 14));
lblGert.setBounds(10, 11, 54, 21);
contentPane.add(lblGert);
lblDeadzone = new JLabel("Deadzone:");
lblDeadzone.setFont(new Font("Tahoma", Font.PLAIN, 14));
lblDeadzone.setBounds(10, 54, 79, 21);
contentPane.add(lblDeadzone);
txtDeadzone = new JTextField();
txtDeadzone.setText("0.5");
txtDeadzone.setBounds(80, 56, 33, 20);
contentPane.add(txtDeadzone);
txtDeadzone.setColumns(10);
JButton btnAbbrechen = new JButton("Abbrechen");
btnAbbrechen.setBounds(290, 94, 119, 23);
btnAbbrechen.setActionCommand("Abbrechen");
btnAbbrechen.addActionListener(this);
contentPane.add(btnAbbrechen);
JButton btnOk = new JButton("OK");
btnOk.setBounds(168, 94, 112, 23);
btnOk.setActionCommand("OK");
btnOk.addActionListener(this);
contentPane.add(btnOk);
}
@Override
publicvoid actionPerformed(ActionEvent e) {
if (e.getActionCommand().equals("Abbrechen")) {
dispose();
}
if (e.getActionCommand().equals("OK")) {
try{
Hauptfenster.setJoystickController(Float.parseFloat(txtDeadzone.getTe
xt()), comboBoxController.getSelectedIndex());
Einstellungen.setDeadzone(Float.parseFloat(txtDeadzone.getText()));
Einstellungen.setControllerName((String)comboBoxController.getSelecte
dItem());
Einstellungen.speichern();
dispose();
}catch (NumberFormatException exc){
Object[] options = {"OK"};
JOptionPane.showOptionDialog(null, "Ungültige
Zahl", "", JOptionPane.DEFAULT_OPTION,
JOptionPane.PLAIN_MESSAGE, null, options, options[0]);
}
}
: Anhang | 116
}
}
Der Motorenschaltplan
: Bildquellenverzeichnis | 117
Bildquellenverzeichnis
Abbildung 1-1:
http://upload.wikimedia.org/wikipedia/commons/3/3d/RaspberryPi.jpg | 25.05.2014; 11:59
Abbildung 1-2:
http://openhardware.pe/wp-content/uploads/2013/03/L298StepperController.jpg | 25.05.2014; 12:01
Abbildung 1-3:
http://cache.lego.com/upload/contentTemplating/PowerfunctionsElementSpecs/otherfiles/downloadC823E977D9
D008D5B83C6E77AFB7688D.jpg | 25.05.2014; 12:03
Abbildung 1-4:
http://www.philohome.com/motors/motorcomp.htm | 25.05.2014; 12:04
Abbildung 1-5:
http://www.philohome.com/motors/motorcomp.htm | 25.05.2014; 12:04
Abbildung 1-6:
http://www.philohome.com/motors/motorcomp.htm | 25.05.2014; 12:04
Abbildung 1-7:
http://i.computer-bild.de/imgs/1/9/2/8/3/4/7/Transcend-SDHC-Class-6-8GB-Speicherkarte-600x450-
1a3ceb942e384ec3.jpg | 25.05.2014; 12:08
Abbildung 1-8:
http://www.testberichte.de/imgs/p_imgs/Digitus+PowerRocket+4000-747277.jpg | 25.05.2014; 12:10
Abbildung 1-9:
http://www.conrad.de/medias/global/ce/9000_9999/9900/9930/9936/993655_LB_00_FB.EPS_1000.jpg |
25.05.2014; 12:11
Abbildung 1-10:
http://pro-jex.de/shop2/bilder/produkte/gross/Logitech-C170-Webcam-Kamera.jpg | 25.05.2014; 12:12
Abbildung 1-11:
http://www.conrad.com/medias/global/ce/9000_9999/9000/9020/9028/902815_RB_00_FB.EPS_1000.jpg |
24.06.2014; 21:59
Abbildung 1-12:
http://www.intorobotics.com/wp-content/uploads/2013/10/rsz_rty6789lojmne43556u67ukymhngfbrvf.png |
24.06.2014; 22:00
Abbildung 1-13:
http://www.amazon.de/Steckbrett-Breadboard-Experimentierboard-Steckplatine-
Kontakte/dp/B009P04XG8/ref=sr_1_2?ie=UTF8&qid=1403640229&sr=8-2&keywords=steckboard | 24.06.2014;
22:03
: Bildquellenverzeichnis | 118
Abbildung 1-14:
https://simple-solutions.de/shop/images/product_images/popup_images/50_0.jpg| 24.06.2014; 22:05
Abbildung 1-15:
http://www.led-tech.de/images/products/resized/LT-362-1264685968.jpg | 24.06.2014; 22:05
Abbildung 1-16:
Eigenkreation mit Exel
Abbildung 2-1:
Screenshot SDFormatter V4.0
Abbildung 2-2:
Screenshot Windows Explorer
Abbildung 2-3:
Screenshot Windows Explorer
Abbildung 2-4:
Screenshot Windows Explorer
Abbildung 2-5:
Eigenes Bild
Abbildung 2-6:
Screenshot Installation NOOBS
Abbildung 2-7:
Screenshot Installation NOOBS
Abbildung 2-8:
Screenshot Installation Raspbian
Abbildung 2-9:
Screenshot Raspbian
Abbildung 2-10:
http://nxus.no-ip.org/main_sub/artikel/pictures/freeware/putty.png | 24.06.2014; 22:08
Abbildung 2-11:
Screenshot PuTTY
Abbildung 2-12:
http://upload.wikimedia.org/wikipedia/commons/d/de/WinSCP_Logo.png | 24.06.2014; 22:10
Abbildung 2-13:
Screenshot WinSCP
Abbildung 2-14:
Screenshot WinSCP
Abbildung 2-15:
Screenshot WinSCP
Abbildung 2-16:
Screenshot Remotedesktop
Abbildung 2-17 :
Screenshot Remotedesktop
: Bildquellenverzeichnis | 119
Abbildung 2-17 :
http://upload.wikimedia.org/wikipedia/commons/thumb/4/44/WIFI_icon.svg/319px-WIFI_icon.svg.png |
25.06.2014; 12:57
Abbildung 2-18 :
http://upload.wikimedia.org/wikipedia/commons/thumb/4/44/WIFI_icon.svg/319px-WIFI_icon.svg.png |
25.06.2014; 12:57
Abbildung 2-19 :
Screenshot Raspbian
Abbildung 2-20 :
Screenshot Raspbian
Abbildung 2-21 :
Screenshot Raspbian
Abbildung 3-1 :
Screenshot Eclipse
Abbildung 3-2 :
Screenshot Eclipse
Abbildung 3-3 :
Screenshot Eclipse
Abbildung 3-4 :
Screenshot Eclipse
Abbildung 3-5:
Screenshot Eclipse
Abbildung 3-6:
Screenshot Eclipse
Abbildung 3-7:
Screenshot Eclipse
Abbildung 3-8:
Screenshot Eclipse
Abbildung 3-9:
Screenshot Eclipse
Abbildung 4-1:
Screenshot WinSCP
Abbildung 4-2:
Screenshot WinSCP
Abbildung 4-3:
http://lego.brandls.info/tt/pfnxtsens_pfcon.jpg | 25.06.2014; 13:07
Abbildung 4-4:
Eigenes Bild
Abbildung 4-5:
http://openhardware.pe/wp-content/uploads/2013/03/L298StepperController.jpg | 25.06.2014; 13:10
: Bildquellenverzeichnis | 120
Abbildung 4-6:
Eigenkreation mit Fritzing (http://www.fritzing.org)
Abbildung 4-7:
http://pi4j.com/images/p1header-large.png | 25.06.2014; 13:10
Abbildung 5-1:
Screenshot Launcher
Abbildung 5-2:
Screenshot Hauptfenster
Abbildung 5-3:
Screenshot Hauptfenster
Abbildung 5-4:
Screenshot
Abbildung 5-5:
Screenshot Tastenbelegung
Abbildung 5-6:
Screenshot Auswahl treffen
Abbildung 5-7:
Screenshot Auswahl zugewiesen
Abbildung 6-1:
Screenshot Webcampanel
Abbildung 6-2:
Screenshot Webcamstream im Client
Abbildung 6-3:
Screenshot Checkbox
Abbildung 6-4:
Screenshot Webcamstream
Abbildung 6-5:
Screenshot Webcam
Abbildung 7-1:
Eigenkreation mit 1-11
Abbildung 7-2:
Screenshot Eclipse
Abbildung 7-3:
Screenshot Eclipse
Abbildung 8-1:
https://www.aimagin.com/media/catalog/product/cache/1/image/9df78eab33525d08d6e5fb8d27136e95/h/c/hc-
sr04-02.jpg | 25.06.2014 18:09
Abbildung 8-2:
http://www.circuitstoday.com/wp-content/uploads/2012/12/HC-SR04-timing-diagram.png | 25.06.2014 18:09
Abbildung 8-5:
Eigenkreation
: Bildquellenverzeichnis | 121
Abbildung 8-4:
https://www.circuitlab.com/circuit/4znzk9/screenshot/540x405/ | 25.06.2014 18:09
Abbildung 8-5:
http://www.hobbytronics.co.uk/image/data/tutorial/raspberry-pi/gpio-pinout.jpg | 25.06.2014 18:09
Top Related