TigerJython | xx für Gymnasien |
Zwei EV3-Roboter können miteinander über das WLAN kommunizieren, indem sie einander Strings zusenden. Dabei läuft auf einem EV3-Brick ein TCP-Server- und auf dem anderen ein TCP-Client-Programm. Unter der Verwendung des Moduls tcpcon aus der TigerJython-Distribution, können mit wenig Aufwand interessante Anwendungen programmiert werden. |
In der Regel spielt es keine Rolle, welcher der beiden Robotern Server und welcher Client ist. Das Server-Programm muss aber immer zuerst gestartet werden. Der Client erstellt danach unter der Verwendung der IP-Adresse des Servers und der Portnummer, welche im Serverprogramm festgelegt ist, eine Verbindung zum Server. Die Verbindung kann über das öffentliche Internet, einen lokalen WLAN-Router oder einen mobiler WLAN-Hotspot, der auf einem Smartphone aktiviert ist, erfolgen. Mehr zur Einrichtung der Kommunikation findet man hier.
Das Modul tcpcom ist eventgesteuert aufgebaut. Der Status der Verbindung wird mit der Callbackfunktion onStateChanged(state, msg) überwacht. Diese wird bei der Erzeugung von TCPServers bzw. TCPClients registriert.
Der Parameter state des Servers kennt folgende Zustände:
TCP.Server.LISTENING TCP.Server.CONNECTED TCP.Server.MESSAGE TCP.Server.TERMINATE |
Server wartet auf eine neue Verbindung Die Verbindung zum Client wurde aufgebaut Der Server hat eine Message msg empfangen Der Server ist beendet |
Der Client kennt folgende Zustände:
TCPClient.CONNECTED TCPClient.MESSAGE TCPClient.DISSCONNECTED |
Verbindung erfolgreich erstellt Der Client hat eine Message msg empfangen Verbindung unterbrochen |
Mit der Funktion sendMessage() können Messages in Form eines Strings vom Server zum Client und umgekehrt gesendet werden. Mehr über die TCP/IP-Programmierung findet man unter tcpcom.
Beispiel 1: Die Roboter stellen Züge dar, die sich auf einer runden Bahn bewegen. Ein Teil der Strecke ist nur einspurig befahrbar. Die Roboter teilen einander via TCP mit, wenn sie am Bahnhof angekommen sind und die Bahn frei ist. Das Serverprogramm wird zuerst gestartet. Nach der Aufbau der Verbindung fährt der Client zuerst seine Runde und hält beim blauen Streifen an, der mit einem zweiten Lichtsensor erkannt wird. Dabei sendet er die Message "go" an den Server. Dann fährt der Server eine Runde und sendet die Message "go" an den Client, sobald er angehalten hat und die Bahn frei ist.
In den folgenden Programmen sind die Importzeilen "from tcpcom import TCPServer" bzw. "from tcpcom import TCPClient" nur für den direkten Modus notwendig. Für den realen Modus muss man diese Zeilen deaktivieren oder löschen. Auf der SDCard ist das Modul tcpcom im Modul ev3robot integriert und muss daher nicht explizit importiert werden. |
#TrainServer.py from ev3robot import * from tcpcom import TCPServer import time def onStateChanged(state, msg): global isWaiting, isStoped, start if state == TCPServer.LISTENING: gear.stop() isWaiting = True if state == TCPServer.CONNECTED: robot.drawString("Connected", 0, 1); playTone(260, 100) if state == TCPServer.MESSAGE: if msg == "go": isWaiting = False start = time.time() print "run" robot = LegoRobot() gear = Gear() robot.addPart(gear) ls1 = LightSensor(SensorPort.S3) robot.addPart(ls1) ls2 = LightSensor(SensorPort.S1) robot.addPart(ls2) port = 5000 server = TCPServer(port, stateChanged = onStateChanged) start = time.time() isWaiting = True while not robot.isEscapeHit(): if isWaiting: continue v1 = ls1.getValue() v2 = ls2.getValue() if v1 > 500: gear.rightArc(0.2) else: gear.leftArc(0.2) if v2 > 300 and v2 < 600 and time.time() - start > 5: server.sendMessage("go") print "ok" gear.stop() isWaiting = True Tools.delay(200) server.terminate() robot.exit() |
Programmcode markieren
|
# TrainClient.py from ev3robot import * from tcpcom import TCPClient import time def onStateChanged(state, msg): global isWaiting, start if state == TCPClient.CONNECTED: print "connected" if state == TCPClient.DISCONNECTED: gear.stop() if state == TCPClient.MESSAGE: if msg == "go": isWaiting = False start = time.time() print "run" robot = LegoRobot() gear = Gear() robot.addPart(gear) ls1 = LightSensor(SensorPort.S3) robot.addPart(ls1) ls2 = LightSensor(SensorPort.S1) robot.addPart(ls2) gear.forward() host = "192.168.0.17" port = 5000 client = TCPClient(host, port, stateChanged = onStateChanged) isWaiting = False if client.connect(): start = time.time() while not robot.isEscapeHit(): if isWaiting: continue v1 = ls1.getValue() v2 = ls2.getValue() if v1 > 500: gear.rightArc(0.2) else: gear.leftArc(0.2) if v2 > 300 and v2 < 600 and time.time() - start > 5: print "ok" gear.stop() client.sendMessage("go") isWaiting = True Tools.delay(200) client.disconnect() robot.exit() |
Programmcode markieren
|
Erklärungen zum Programmcode:
host = "192.168.0.4": IP-Adresse des Roboters, auf welchen das Serverprogramm läuft | |
if v2 > 500 and v2 < 750 and time.time() - start > 5: Falls der Roboter mit seinem Lichtsensor den blauen Streifen erfasst hat und die Zeit seit dem letzten Start grösser als 5 Sekunden ist, hält er an | |
client.sendMessage("go"): Mit dieser Message wird die Bahn für den Server-Roboter frei gegeben |
Beispiel 2: Die TCP-Kommunikation funktioniert auch im Simulationsmodus. Zum Testen kann man das Server- und das Client-Programm auf dem gleichen Computer ausführen, indem man die TigerJython-IDE zweimal startet und die IP-Adresse localhost verwendet. In diesem Beispiel werden die Züge jeweils mit einem blauen Streifen gestoppt. Die Roboter registrieren den blauen Streifen mit einem Lichtsensor. Das Hintergrundbild für die Simulation train.png können Sie hier herunterladen. Klicken Sie mit der rechten Maustaste auf das nebenstehende Bild, wählen Sie Grafik speichern unter und speichern Sie das Bild im Unterverzeichnis sprites des Verzeichnisses, in dem sich ihr Programm befindet.
|
# SimTrainServer.py from simrobot import * from tcpcom import TCPServer import time def onStateChanged(state, msg): global isWaiting, isStoped, start if state == TCPServer.LISTENING: gear.stop() isWaiting = True if state == TCPServer.CONNECTED: robot.drawString("Connected", 0, 1); playTone(260, 100) if state == TCPServer.MESSAGE: if msg == "go": isWaiting = False start = time.time() print "run" RobotContext.useBackground("sprites/train.png") RobotContext.setStartPosition(230, 415) RobotContext.setStartDirection(180) robot = LegoRobot() gear = Gear() robot.addPart(gear) ls1 = LightSensor(SensorPort.S3) robot.addPart(ls1) ls2 = LightSensor(SensorPort.S1) robot.addPart(ls2) port = 5000 server = TCPServer(port, stateChanged = onStateChanged) start = time.time() isWaiting = True while not robot.isEscapeHit(): if isWaiting: continue v1 = ls1.getValue() v2 = ls2.getValue() if v1 > 800: gear.rightArc(0.2) else: gear.leftArc(0.2) if v2 > 500 and v2 < 750 and time.time() - start > 5: server.sendMessage("go") print "ok" gear.stop() isWaiting = True Tools.delay(200) server.terminate() robot.exit() |
Programmcode markieren
|
# SimTrainClient.py from simrobot import * from tcpcom import TCPClient import time def onStateChanged(state, msg): global isWaiting, start if state == TCPClient.CONNECTED: print "connected" if state == TCPClient.DISCONNECTED: gear.stop() if state == TCPClient.MESSAGE: if msg == "go": isWaiting = False start = time.time() print "run" RobotContext.useBackground("sprites/train.png") RobotContext.setStartPosition(285, 350) RobotContext.setStartDirection(-20) robot = LegoRobot() gear = Gear() robot.addPart(gear) ls1 = LightSensor(SensorPort.S3) robot.addPart(ls1) ls2 = LightSensor(SensorPort.S1) robot.addPart(ls2) gear.forward() host = "localhost" port = 5000 client = TCPClient(host, port, stateChanged = onStateChanged) isWaiting = False if client.connect(): start = time.time() while not robot.isEscapeHit(): if isWaiting: continue v1 = ls1.getValue() v2 = ls2.getValue() if v1 > 800: gear.rightArc(0.2) else: gear.leftArc(0.2) if v2 > 500 and v2 < 750 and time.time() - start > 5: print "ok" gear.stop() client.sendMessage("go") isWaiting = True Tools.delay(200) client.disconnect() robot.exit() |
Programmcode markieren
|
Erklärungen zum Programmcode:
host = "localhost": Anstelle der IP-Adresse des Servers kann localhost verwendet werden | |
if v2 > 500 and v2 < 750 and time.time() - start > 5: Falls der Roboter mit seinem Lichtsensor den blauen Streifen erfasst hat und die Zeit seit dem letzten Start grösser als 5 Sekunden ist, hält er an | |
client.sendMessage("go"): Mit dieser Message wird die Bahn für den Server-Roboter frei gegeben |
Aufgaben Serie18: |
1) |
Synchron fahren und stoppen.
|
|
|