Ein Roboter kann beliebig viele Informationen speichern und mit Hilfe der gespeicherten Daten lernen selbständig bestimmte Aufgaben zu erledigen. In unseren Beispielen lernt der Roboter eine Hindernisbahn selbstständig durchzufahren. |
Beispiel 1: Der Roboter kennt den Weg Er geht also die Liste memory = [0, 1, 1, 0] der Reihe nach durch, biegt bei der ersten Abzweigung nach links, bei der zweiten nach rechts usw. Dazwischen fährt er immer die gleiche Anzahl Millisekunden vorwärts. |
#Ro12a.py from simrobot import * #from ev3robot import * RobotContext.useBackground("sprites/bg.gif") RobotContext.setStartPosition(310, 470) robot = LegoRobot() gear = Gear() robot.addPart(gear) tMove = 3200 tTurn = 545 memory = [0, 1, 1, 0] gear.forward(tMove) for i in memory: if i == 0: gear.left(tTurn) gear.forward(tMove) elif i == 1: gear.right(tTurn) gear.forward(tMove) robot.exit() |
Programmcode markieren
|
Erklärungen zum Programmcode:
tTurn , tMove : um die Anzahl Millisekunden für die Drehung und Vorwärtsfahren einfacher anpassen zu können, verwendet man Variablen | |
memory = [0, 1, 1, 0]: Elemente einer Liste werden in den eckigen Klammer aufgezählt | |
for i in memory(): mit for-Schleife kann die Liste memory "durchgelaufen" werden |
Beispiel 2: Der Roboter wird durch einen Menschen "angelernt" Falls der Button LEFT (in der Simulation die Cursortaste LEFT) gedrückt wurde dreht er 90° nach links bei der Taste RIGHT dreht er nach rechts. Bei jeder Drehung speichert er 0 bzw. 1 in der Liste memory, die zu Beginn leer ist. Mit dem Befehl memory.append(0) wird das Element 0 zu der Liste hinzugefügt. |
Die Lernphase wird mit der Taste ESCAPE beendet (kann auch vor Ende des Parcours sein). Mit Drücken der ENTER-Taste fährt der Roboter anschliessend die Bahn selbständig durch und verwendet dabei die gespeicherten Informationen. Im Simulationsmodus muss der Roboter aber zuerst mit dem Befehl reset an die Startposition zurück versetzt werden. Beim realen Roboter versetzt man den Roboter an die Startposition und drückt danach die ENTER-Taste auf dem Brick. Mit der Taste DOWN wird das Programm beendet. |
#Ro12b.py from simrobot import * #from ev3robot import * RobotContext.useBackground("sprites/bg.gif") RobotContext.setStartPosition(310, 470) RobotContext.showStatusBar(30) robot = LegoRobot() gear = Gear() robot.addPart(gear) tMove = 3200 tTurn = 545 memory = [] gear.forward(tMove) # learning while not robot.isEscapeHit(): if robot.isLeftHit(): gear.left(tTurn) memory.append(0) gear.forward(tMove) elif robot.isRightHit(): gear.right(tTurn) memory.append(1) gear.forward(tMove) robot.drawString("Memory: " + str(memory), 0, 1) print(memory) # running while not robot.isDownHit(): while not robot.isEnterHit(): pass robot.reset() gear.forward(tMove) for i in memory: if i == 0: gear.left(tTurn) gear.forward(tMove) elif i == 1: gear.right(tTurn) gear.forward(tMove) robot.exit() |
Programmcode markieren
|
Erklärungen zum Programmcode:
memory = [] : memory ist zu Beginn eine leere Liste | |
memory.append(0): beim Linksabbiegen wird eine 0 in die Liste hinzugefügt | |
memory.append(1): beim Rechtsabbiegen wird eine 1 hinzugefügt | |
robot.reset: nur im Simulationsmodus, der Roboter wird an die Ausgansposition zurück versetzt |
Beispiel 3: In der Lernphase wird die Infrarot-Fernsteuerung verwendet Der Roboter wird während der "learning"-Phase mit den Tasten "oben links" und "oben rechts" auf der Infrarot-Fernsteuerung angelernt. Analog wie im vorhergehenden Beispiel speichert der Roboter während der "learning"-Phase die Informationen in der Liste memory. Mit dem Drücken der Taste "unten rechts" auf der Fernsteuerung wird die "running"-Phase gestartet. Der Roboter muss vorher an die Ausgangsposition versetzt werden. Danach fährt er selbständig mit Hilfe der Liste memory den Parcours ab. Das Programm kann mit der Taste "unten links" oder mit Drücken des Buttons ESCAPE auf dem Brick beendet werden |
# Ro12c.py from ev3robot import * robot = LegoRobot() gear = Gear() robot.addPart(gear) irs = IRRemoteSensor(SensorPort.S1) robot.addPart(irs) tMove = 3200 tTurn = 545 memory = [] gear.forward(tMove) # learning while not robot.isEscapeHit() and isRunning: command = irs.getCommand() if command == 1: #top left gear.left(tTurn) memory.append(0) print(memory) gear.forward(tMove) elif command == 3:#top right gear.right(tTurn) memory.append(1) print(memory) gear.right(tTurn) elif command == 2:#botton left gear.stop() # running #set the robot at the startposition elif command == 4: #botton right gear.forward(tMove) for i in memory: if i == 0: gear.left(tTurn) gear.forward(tMove) else: gear.right(tTurn) gear.forward(tMove) elif command == 2: gear.stop() isRunning = False robot.exit() |
Programmcode markieren
|
Erklärungen zum Programmcode:
irs.getCommand: gibt die Nummer des gedrückten Buttons der Fernsteuerung zurück |
Beispiel 4: Touchsensoren und Timer verwenden, um eine Bahn mit beliebig langen Wegstücken durchzufahren. |
Danach dreht er 90° nach links und fährt vorwärts. Wenn er innert einer kurzen Zeit (hier 2 Sekunden) wieder eine Wand berührt, so hat er die falsche Richtung gewählt. Er dreht um 180° und fährt in der neuen Richtung. Wie in den vorhergehenden Beispielen speichert er 0 für Links- und 1 für Rechtsdrehung. Da er diesmal bei jeden Wegstück zwei Informationen (moveTime und 0 bzw. 1 für die Drehrichtung), besteht die Liste memory aus Zahlenpaaren, die hier als node bezeichnet werden. Die "learning"-Phase wird mit ESCAPE beendet. Dann wartet der Roboter bis die Taste ENTER gedrückt wurde und fährt die Bahn selbständig durch. Im Realmodus muss der Roboter vor dem Drücken der ENTER-Taste an die Startposition versetzt werden. |
# Ro12d.py from simrobot import * #from ev3robot import * import time RobotContext.useObstacle("sprites/bg2.gif", 250, 250) RobotContext.setStartPosition(410, 480) RobotContext.showStatusBar(30) robot = LegoRobot() gear = Gear() robot.addPart(gear) ts = TouchSensor(SensorPort.S3) robot.addPart(ts) startTime = time.clock() moveTime = 0 turnTime = 545 backTime = 600 memory = [] gear.forward() #learning while not robot.isEscapeHit(): if ts.isPressed(): dt = time.clock() - startTime gear.backward(backTime) if dt > 2: moveTime = int(dt * 1000) - backTime # save long-track time node = [moveTime, 0] memory.append(node) gear.left(turnTime) # turning left else: memory.pop() node = [moveTime, 1] memory.append(node) gear.right(2 * turnTime) # turning right robot.drawString("Memory: " + str(memory), 0, 1) print(memory) gear.forward() startTime = time.clock() gear.stop() #running while not robot.isDownHit(): while not robot.isEnterHit(): pass robot.reset() for node in memory: moveTime = node[0] k = node[1] gear.forward(moveTime) if k == 0: gear.left(turnTime) elif k == 1: gear.right(turnTime) gear.forward() robot.exit() |
Programmcode markieren
|
Erklärungen zum Programmcode:
dt = time.clock() - startTime : die Zeit zwischen zwei aufeinander folgenden Wandberührungen | |
if dt > 2 : falls die Zeit zur nächsten Wandberührung zu kurz ist, war die Drehung nach links falsch. Mit der Drehung um 180° wird diese zur Drehung um 90° hach rechts korrigiert | |
int(dt * 1000) -backTime: der Timer gibt die Zeit in Sekunden zurück. Diese wird Millisekunden umgerechnet | |
node = [moveTime, 0] : die Liste node besteht aus zwei Werten: der erste für Zeit, die der Roboter für einen Weg benötigt, der zweite für links- bzw. rechtsdrehen | |
memory.append(node) : in die List memory wird jeweils eine Liste mit zwei Werten hinzugefügt | |
memory.pop(): bei einer Rechtsdrehung muss das letzte Element im Memory zuerst gelöscht werden, da der erste Drehversuch nach links fehlerhaft war |
Beispiel 5: Lichtsensoren verwenden, um einem Weg mit Abzweigungen zu folgen. Die Bewegung auf dem schwarzen Streifen wird in der Funktion keepOnTrack() definiert. An den Kreuzungen verwendet man, wie in der vorhergehenden Aufgabe, den Timer. Mit der Taste ESCAPE wird der Roboter am Ende des Parcours angehalten. Dann setzt man ihn wieder an die Startposition (in der Simulation mit dem Befehl reset()) und drückt die Taste ENTER. Danach fährt der Roboter die Bahn ab und verwendet dabei die Informationen, die er in der Liste memory gespeichert hat. |
#Ro12e.py from simrobot import * #from ev3robot import * import time RobotContext.useBackground("sprites/learntrack1.gif") RobotContext.setStartPosition(385, 490) def keepOnTrack(): if vL < 500 and vR < 500: gear.forward() elif vL < 500 and vR > 500: gear.leftArc(0.1) elif vL > 500 and vR < 500: gear.rightArc(0.1) robot = LegoRobot() gear = Gear() robot.addPart(gear) ls1 = LightSensor(SensorPort.S1)#right ls2 = LightSensor(SensorPort.S2)#left robot.addPart(ls1) robot.addPart(ls2) gear.setSpeed(30) memory = [] id = 0 # learning startTime = time.time() while not robot.isEscapeHit(): vL = ls2.getValue() vR = ls1.getValue() keepOnTrack() if vL > 500 and vR > 500: if time.time() - startTime > 2: gear.backward(100) gear.left(900) memory.append(0) gear.forward() elif memory != []: memory.pop() memory.append(1) gear.right(1800) print(memory) startTime = time.time() gear.stop() # running while not robot.isEscapeHit(): while not robot.isEnterHit(): pass robot.reset() id = 0 while not robot.isEscapeHit(): vR = ls1.getValue() vL = ls2.getValue() keepOnTrack() if vL > 500 and vR > 500: gear.stop() if len(memory) == id: break if memory[id] == 0: gear.left(900) else: gear.right(900) id += 1 gear.stop() robot.exit() |
Programmcode markieren
|
Erklärungen zum Programmcode:
print memory : die Liste memory wird im Ausgabefenster des TigerJython-Editors ausgegeben | |
while not robot.isEnterHit(): pass So lange nicht die Taste Enter gedrückt wurde, passiert nichts. Diese "Warte-Schleife" wird eingebaut, damit man den realen Roboter an die Ausgangsposition setzen kann. |
Aufgaben: Serie 12 |
1) |
Lerne den Roboter die nebenstehende Bahn durchzufahren, in dem du die Tasten LEFT, RIGHT, UP für vorwärts fahren und DOWN für stoppen verwendest. Der Roboter speichert die Entscheiden links bzw. rechts und die Zeit, die er für die geraden Wege benötigt im Memory. Für die Simulation kannst du das Hintergrundbild bg3.gif verwenden: RobotContext.useBackground("sprites/bg3.gif")
RobotContext.setStartPosition(410, 475)
|
|
|
2) |
Der Roboter soll mit Hilfe eines Colorsensors und eines Timers lernen die nebenstehende Bahn durchzufahren. Anschliessend soll er die Bahn selbständig (ohne die Wände zu berühren durchfahren. Für die Simulation kannst du das Hintergrundbild colorparcours.png verwenden. RobottContext.useBackground("sprites/colorparcours.png")
RobotContext.setStartPosition(35, 245)
RobotContext.setStartDirection(0)
|
|
|
3) |
Erstelle mit schwarzen Streifen und einer weissen Unterlage eine ähnliche Bahn wie im Beispiel 5. Dein EV3 mit zwei Lichtsensoren soll lernen diese Bahn abzufahren. Im Simulationsmodus kannst du die Hintergrundbilder learntrack2.gif, learntrack3.gif und learntrack4.gif verwenden. |
|
|
4) |
Verwende im Simulationsmodus die Bahn learntrack4.gif. Der Roboter lernt mit Hilfe seiner beiden Lichtsensoren die Bahn vom Start zu Ziel abzufahren (siehe Beispiel 5). Vor dem Ziel wird er mit der Taste Esc angehalten. Danach rechnet er die gespeicherte Liste memory um, so dass er den Parcours vom Ziel zum Start abfahren kann. Mit Drücken der Taste Enter kehrt er um 180° um und fährt mit Hilfe der umgerechneten Liste zum Start zurück. Anleitung: Mit dem Befehl memory.reverse() kannst du die Reihenfolge der Elemente in der Liste umkehren (das letzte Element wird das erste). Teste dein Programm auch mit der Bahn learntrack2.gif. |
|
|
5) |
Der EV3-Roboter soll im Teachmode lernen, einen Kanal, welcher aus rechtwinklig stehenden Wegstücken besteht, durchzufahren. Löse die Aufgaben im Simulationsmodus mit dem Hintergrundbild "bg2.gif". Für die Steuerung im Teachmode verwendest du die Cursortasten wie folgt:
Da der Roboter keine Sensoren hat, musst du die Vorwärtsbewegung jeweils mit dem Button UP starten und mit dem Button DOWN beenden und dabei die Zeit messen. Anleitung: Es sinnvoll in der Liste memory für jede Teilstrecke 2 Werte zu speichern: die Zeit, die der Roboter zum Durchfahren braucht und 0 bzw. 1 für die darauf folgende Drehung. Dieses Zahlenpaar bezeichnest du als node und fügst es nach jeder Drehung zu der Liste hinzu. dt = time.time() - startTime In der running-Phase gehst du die Liste wie folgt durch: for node in memory:
|
|