Logistieke Robots/les 3: verschil tussen versies
(31 tussenliggende versies door 2 gebruikers niet weergegeven) | |||
Regel 2: | Regel 2: | ||
== Morsy besturen met Python == | == Morsy besturen met Python == | ||
In de vorige les hebben we gezien dat de controller van Morsy veel complexer wordt als we hem autonoom aan willen sturen. Wanneer we Morsy nog meer taken willen geven, en wanneer we Morsy in een groep willen laten werken, zijn de logic bricks niet meer toereikend. Daarom gaan we Blender combineren met de programmeertaal Python. | In de vorige les hebben we gezien dat de controller van Morsy veel complexer wordt als we hem autonoom aan willen sturen. Wanneer we Morsy nog meer taken willen geven, en wanneer we Morsy in een groep willen laten werken, zijn de logic bricks niet meer toereikend. Daarom gaan we Blender combineren met de programmeertaal Python. Het eindresultaat van deze les is: https://www.youtube.com/watch?v=-TvRNqFqew8. | ||
Controleer eerst of de juiste versie van Python op je systeem geïnstalleerd is, op de juiste plaats. (Zie: [[../Python installeren|Python installeren]] voor verdere aanwijzingen.) In sommige gevallen is Python geïnstalleerd als onderdeel van Blender. | Controleer eerst of de juiste versie van Python op je systeem geïnstalleerd is, op de juiste plaats. (Zie: [[../Python installeren|Python installeren]] voor verdere aanwijzingen.) In sommige gevallen is Python geïnstalleerd als onderdeel van Blender. | ||
== Blender combineren met programmeertaal Python == | == Blender combineren met programmeertaal Python == | ||
In deze les gebruiken we [https://googledrive.com/host/0B4Wf_Tca5KDuNnFUWTc4R09jblU/logistieke-robots/warehouse.blend warehouse.blend]. Deze omgeving zullen we gedurende de rest van het project gebruiken. Het openen van het bestand gaat nu anders omdat we de Python output willen zien. | In deze les gebruiken we [https://googledrive.com/host/0B4Wf_Tca5KDuNnFUWTc4R09jblU/logistieke-robots/warehouse.blend warehouse.blend]. Deze omgeving zullen we gedurende de rest van het project gebruiken. Het openen van het bestand gaat nu anders omdat we de Python output willen zien. Dit is verschillend voor de Windows en voor de OS X versie van Blender. | ||
=== OS X: Blender opstarten met Terminal === | === OS X: Blender opstarten met Terminal === | ||
Regel 15: | Regel 15: | ||
[[Bestand:osx-show-package.png|350px|Show Package contents]] | [[Bestand:osx-show-package.png|350px|Show Package contents]] | ||
Open vervolgens het blender executable bestand via het openen van de volgende folders: | Open vervolgens het blender executable bestand via het openen van de volgende folders: <code>Contents > MacOS > blender </code> | ||
[[Bestand:osx-blender-terminal.png|700px|Blender starten met terminal]] | [[Bestand:osx-blender-terminal.png|700px|Blender starten met terminal]] | ||
Regel 44: | Regel 44: | ||
Blender Game Engine Finished | Blender Game Engine Finished | ||
</pre> | </pre> | ||
Voor hulp zie: https://www.youtube.com/watch?v=9dRd-pU2dKQ | |||
== Ontwikkelen van een controller in Python == | == Ontwikkelen van een controller in Python == | ||
Regel 77: | Regel 79: | ||
Dit heet een script. Dit script bestaat uit verschillende onderdelen. | Dit heet een script. Dit script bestaat uit verschillende onderdelen. | ||
* (r. 1) <code>import bge</code> importeert de Blender Game Engine module voor Python. In deze module is onder andere de functie <code>logic.getCurrentController()</code> gedefinieerd. | * (r. 1) <code>import bge</code> importeert de Blender Game Engine module voor Python. In deze module is onder andere de functie <code>logic.getCurrentController()</code> gedefinieerd. | ||
* (r. 4-15) De definitie van de functie <code>main()</code>; | * (r. 4-15) De definitie van de functie <code>main()</code>; r.4 bevat de "function header"; de opdrachten in r.5-15 vormen de "body" van de functie. | ||
* (r. 17) Een aanroep van de functie <code>main()</code>: de opdrachten in de definitie daarvan worden uitgevoerd. | * (r. 17) Een aanroep van de functie <code>main()</code>: de opdrachten in de definitie daarvan worden uitgevoerd. | ||
Regel 85: | Regel 87: | ||
# <code>main() </code> - aanroep van de functie main. De opdrachten in de definitie (“body”) van de functie main worden uitgevoerd. | # <code>main() </code> - aanroep van de functie main. De opdrachten in de definitie (“body”) van de functie main worden uitgevoerd. | ||
=== Stap 2: | === Stap 2: Sensoren en actuatoren toevoegen === | ||
Als we op ENTER (ofwel Return) drukken willen we dat Morsy naar de voorste kast gaat lopen. Ga door de volgende stappen heen om de juiste sensors en actuators toe te voegen: | Als we op ENTER (ofwel Return) drukken willen we dat Morsy naar de voorste kast gaat lopen. Ga door de volgende stappen heen om de juiste sensors en actuators toe te voegen: | ||
# Verander de Always sensor in een Keyboard sensor met als Key de ENTER knop. Geef deze sensor de naam ‘Start’ | # Verander de Always sensor in een Keyboard sensor met als Key de ENTER knop. Geef deze sensor de naam ‘Start’ | ||
# Voeg een Steering actuator toe. Laat deze de naam ‘Steering’ houden en over de –X as bewegen. | # Voeg een Steering actuator toe. Laat deze de naam ‘Steering’ houden en over de –X as bewegen. | ||
# Voeg een | # Voeg een Collision sensor genaamd ‘AtTarget’ toe; link deze aan de Python controller. | ||
Dit zijn alle actuators en sensors die we nodig hebben om de genoemde taak uit te voeren. | Dit zijn alle actuators en sensors die we nodig hebben om de genoemde taak uit te voeren. | ||
Regel 103: | Regel 105: | ||
<syntaxhighlight lang="Python"> | <syntaxhighlight lang="Python"> | ||
import bge | import bge | ||
cont = bge.logic.getCurrentController() | cont = bge.logic.getCurrentController() | ||
start = cont.sensors[ | start = cont.sensors["Start"] | ||
collision = cont.sensors[ | collision = cont.sensors["AtTarget"] | ||
steering = cont.actuators["Steering"] | |||
def main(): | def main(): | ||
Regel 126: | Regel 130: | ||
cont = bge.logic.getCurrentController() | cont = bge.logic.getCurrentController() | ||
start = cont.sensors[ | start = cont.sensors["Start"] | ||
collision = cont.sensors[ | collision = cont.sensors["AtTarget"] | ||
steering | steering = cont.actuators["Steering"] | ||
def main(): | def main(): | ||
steering.target = | steering.target = "Shelf_8" | ||
cont.activate(steering) | cont.activate(steering) | ||
Regel 141: | Regel 145: | ||
Wanneer je nu in de play modus gaat en op ENTER drukt zie je dat Morsy naar Shelf_8 gaat lopen. | Wanneer je nu in de play modus gaat en op ENTER drukt zie je dat Morsy naar Shelf_8 gaat lopen. | ||
In deze stap ga je zelf uitzoeken hoe Morsy heen en weer loopt naar de kast | In deze stap ga je zelf uitzoeken hoe Morsy heen en weer loopt naar de kast. | ||
Tips: | Tips: | ||
* maak (via het Properties-venster) een Game Property aan voor <code>Desk_11</code> - met als naam (bijvoorbeeld) <code>Desk</code>, en voor <code>Shelf_8</code> (bijvoorbeeld <code>Shelf</code>). Deze gebruik je in de collision-sensor, om alleen een collision met dit object te detecteren. In Python heet dit <code>collision.propName</code>. | |||
** alleen de naam van de property is hier van belang: de waarde gebruiken we in dit geval niet. | |||
* klik in de collision sensor de Tap button aan om maar 1 trigger te geven bij aanraking van de tafel of kast. | |||
Het is niet erg als je er zelf nog niet helemaal uit bent gekomen. Juist als het niet werkt zoals je wilt leer je hier meer van doordat je de verkeerde code moet herstellen. Wanneer je er niet uit komt kun je naar onderstaande uitwerking kijken: | Het is niet erg als je er zelf nog niet helemaal uit bent gekomen. Juist als het niet werkt zoals je wilt leer je hier meer van doordat je de verkeerde code moet herstellen. Wanneer je er niet uit komt kun je naar onderstaande uitwerking kijken: | ||
<syntaxhighlight lang="Python"> | |||
import bge | |||
cont = bge.logic.getCurrentController() | |||
start = cont.sensors["Start"] | |||
collision = cont.sensors["AtTarget"] | |||
steering = cont.actuators["Steering"] | |||
def main(): | |||
collision.propName = "Shelf" | |||
steering.target = "Shelf_8" | |||
cont.activate(steering) | |||
def handleCollision(): | |||
if collision.propName == "Shelf": | |||
steering.target = "Desk_11" | |||
collision.propName = "Desk" | |||
else: | |||
steering.target = "Shelf_8" | |||
collision.propName = "Shelf" | |||
cont.activate(steering) | |||
if start.positive: | |||
print("Initialize") | |||
main() | |||
elif collision.positive: | |||
print("Collision") | |||
handleCollision() | |||
else: | |||
print("No action") | |||
</syntaxhighlight> | |||
Opmerkingen: | |||
* we gebruiken de ENTER key om Morsy in beweging te zetten. Hiervoor gebruiken we een aparte functie <code>initialize()</code>. | |||
* als Morse direct van start gaat, zonder dat je de ENTER key gebruikt hebt, kan er sprake zijn van een collision-event: als de collision-sensor geen Property heeft (in Python: <code>propName == ""</code>), dan detecteert deze sensor een collision met elk willekeurig object - dus ook met het desk waar deze naast staat. Je kunt dit voorkomen door in het sensor-venster een willekeurige string als Property in te vullen - bijvoorbeeld "x". | |||
** Ga na in de logfile of er al direct sprake is van een collision. | |||
* we hebben een aantal print-statements toegevoegd om in de logfile na te gaan wat er gebeurt. Kijk of je de logfile begrijpt. (Het script wordt ook uitgevoerd bij de "negative" overgangen van de sensoren). | |||
Voor hulp zie: https://www.youtube.com/watch?v=y36ZGsFDA2E | |||
Variaties: | |||
* Hoe kun je Morsy direct van start laten gaan in de play modus, zonder de ENTER key te gebruiken? | |||
* In deze uitwerking gebruiken we één controller, met één script, met twee sensoren. We moeten in het script dan uitzoeken met welk sensor-event we te maken hebben. Je kunt ook aparte controllers gebruiken voor het opstarten, en voor het afhandelen van een collision. Je gebruikt dan ook twee scripts. Probeer dit uit. | |||
plus: visualiseer pakket https://www.youtube.com/watch?v=wJYlWa5D0hc |
Huidige versie van 31 mrt 2015 om 18:11
Morsy besturen met Python
In de vorige les hebben we gezien dat de controller van Morsy veel complexer wordt als we hem autonoom aan willen sturen. Wanneer we Morsy nog meer taken willen geven, en wanneer we Morsy in een groep willen laten werken, zijn de logic bricks niet meer toereikend. Daarom gaan we Blender combineren met de programmeertaal Python. Het eindresultaat van deze les is: https://www.youtube.com/watch?v=-TvRNqFqew8.
Controleer eerst of de juiste versie van Python op je systeem geïnstalleerd is, op de juiste plaats. (Zie: Python installeren voor verdere aanwijzingen.) In sommige gevallen is Python geïnstalleerd als onderdeel van Blender.
Blender combineren met programmeertaal Python
In deze les gebruiken we warehouse.blend. Deze omgeving zullen we gedurende de rest van het project gebruiken. Het openen van het bestand gaat nu anders omdat we de Python output willen zien. Dit is verschillend voor de Windows en voor de OS X versie van Blender.
OS X: Blender opstarten met Terminal
Ga naar de Blender applicatie en open de Package Contents van Blender.
Open vervolgens het blender executable bestand via het openen van de volgende folders: Contents > MacOS > blender
Als Blender opstart, kun je via File>Open
het bestand “warehouse.blend” openen.
Windows:
Open Blender op de gebruikelijke manier. Ga naar de Info Window en klik op Window >Toggle System Console
. Er is nu een extra scherm in beeld.
Wanneer je de file “warehouse.blend” geopend hebt, zie je in het window linksonder een Tekst Editor. Hier kun je een Python controller ontwikkelen.
Controleren of Python werkt in Blender
Om te testen of de link tussen Blender en Python werkt, voeren we de volgende stappen uit:
- Voeg aan Robot_11 (de voorste) een Always sensor toe.
- Maak een nieuw Python script aan:
- klik op de "+" onderin het Text Editor venster (naast de naam van het bestand).
- verander de naam van het bestand in "Text.py"
- typ in de Text Editor:
print(“Hello”)
- Voeg aan Robot_11 een Python controller:
- Selecteer als script voor deze Python-controller: "Text.py"
- Link de controller met de sensor:
- Ga na de spel modus (of, voor OS X, naar de Terminal) en kijk naar de console. Dit moet er nu in de console te zien zijn:
Blender Game Engine Started Hello Blender Game Engine Finished
Voor hulp zie: https://www.youtube.com/watch?v=9dRd-pU2dKQ
Ontwikkelen van een controller in Python
Nu je weet hoe je Python aan Blender moet koppelen, kunnen we een Python controller maken. We gaan Morsy, nu genaamd Robot_11, naar een kast laten lopen om een artikel op te halen en in de box te zetten op tafel. Voordat we hieraan kunnen beginnen moeten we begrijpen hoe je sensoren kunt opvangen en actuatoren kunt aansturen via een Python controller.
Morsy laten lopen door een Python controller
Wat je in deze paragraaf gaat leren lijkt op wat je geleerd hebt in les 2, het autonoom laten ophalen van objecten en naar een bepaald doel brengen, maar nu doen we dat via een Python controller.
Stap 1: Onderdelen van een script
Blender heeft al een opzet voor hoe je een robot moet aansturen. Ga in de Tekst editor window naar Templates > Python> GameLogic Simple
. Je ziet nu de volgende code verschijnen:
import bge
def main():
cont = bge.logic.getCurrentController()
own = cont.owner
sens = cont.sensors['mySensor']
actu = cont.actuators['myActuator']
if sens.positive:
cont.activate(actu)
else:
cont.deactivate(actu)
main()
Dit heet een script. Dit script bestaat uit verschillende onderdelen.
- (r. 1)
import bge
importeert de Blender Game Engine module voor Python. In deze module is onder andere de functielogic.getCurrentController()
gedefinieerd. - (r. 4-15) De definitie van de functie
main()
; r.4 bevat de "function header"; de opdrachten in r.5-15 vormen de "body" van de functie. - (r. 17) Een aanroep van de functie
main()
: de opdrachten in de definitie daarvan worden uitgevoerd.
Het is belangrijk om te begrijpen hoe een script werkt. Wanneer deze controller geactiveerd wordt (bijvoorbeeld door een sensor), wordt het script uitgevoerd, en gebeurt er het volgende:
import bge
- Het script importeert de module ‘bge’ en beschikt zo over alle gedefinieerde functies in de bge module.def main():
- definieert de functie main met de daarop volgende opdrachten.main()
- aanroep van de functie main. De opdrachten in de definitie (“body”) van de functie main worden uitgevoerd.
Stap 2: Sensoren en actuatoren toevoegen
Als we op ENTER (ofwel Return) drukken willen we dat Morsy naar de voorste kast gaat lopen. Ga door de volgende stappen heen om de juiste sensors en actuators toe te voegen:
- Verander de Always sensor in een Keyboard sensor met als Key de ENTER knop. Geef deze sensor de naam ‘Start’
- Voeg een Steering actuator toe. Laat deze de naam ‘Steering’ houden en over de –X as bewegen.
- Voeg een Collision sensor genaamd ‘AtTarget’ toe; link deze aan de Python controller.
Dit zijn alle actuators en sensors die we nodig hebben om de genoemde taak uit te voeren.
Stap 3: Triggers ontvangen en versturen door de Python controller
In de vorige lessen hadden we een sensor, bijvoorbeeld een Keyboard sensor, aan een And controller gekoppeld. Wanneer je de juiste toets aanraakt op je toetsenbord gaat er een positieve ‘trigger’ naar de And controller die de bijbehorende actuator activeert.
Nu moeten we de Start trigger op zien te vangen in de Python controller. Doe dit als volgt:
- Het script moet de controller kunnen aanroepen waar de sensoren en actuatoren aan gekoppeld zijn. Dit kan door de functie
bge.logic.getCurrentController()
- Vervolgens moet de controller kunnen herkennen welke van de inkomende sensoren een trigger geeft om een juiste actuator aan te roepen. Je kunt deze sensoren vinden via
cont.sensors[“Start”]
encont.sensors[“AtTarget”]
Om de code overzichtelijk te houden kun je verwijzingen maken naar de sensoren en actuatoren. Je mag deze namen zelf verzinnen of de volgende gebruiken:
import bge
cont = bge.logic.getCurrentController()
start = cont.sensors["Start"]
collision = cont.sensors["AtTarget"]
steering = cont.actuators["Steering"]
def main():
# define function main…
main()
- Bij het indrukken van de ENTER key, willen we dat Morsy zijn taak uit gaat voeren. Zowel het indrukken als het loslaten van de ENTER key geeft een trigger aan de controller. Het indrukken is een positive pulse en loslaten een negative pulse. Via een boolean (met waarde TRUE of FALSE) wordt aangegeven of er een pulse gegeven wordt. We willen dat de main() alleen aangeroepen wordt als start.positive TRUE is. Omdat start.positive een boolean is kun je dit als volgt opschrijven:
if start.positive
main()
(Let op: een Tab in Python staat gelijk aan 4 spaties en is nodig om aan te geven wat er moet gebeuren als de conditie van de if TRUE
is)
- Zorg ervoor dat in de definitie van de functie
main()
de Steering actuator geactiveerd wordt en naar Shelf_8 toe gaat (de voorste kast). De code ziet er nu als volgt uit:
import bge
cont = bge.logic.getCurrentController()
start = cont.sensors["Start"]
collision = cont.sensors["AtTarget"]
steering = cont.actuators["Steering"]
def main():
steering.target = "Shelf_8"
cont.activate(steering)
if start.positive:
main()
Stap 4: Script afmaken
Wanneer je nu in de play modus gaat en op ENTER drukt zie je dat Morsy naar Shelf_8 gaat lopen.
In deze stap ga je zelf uitzoeken hoe Morsy heen en weer loopt naar de kast.
Tips:
- maak (via het Properties-venster) een Game Property aan voor
Desk_11
- met als naam (bijvoorbeeld)Desk
, en voorShelf_8
(bijvoorbeeldShelf
). Deze gebruik je in de collision-sensor, om alleen een collision met dit object te detecteren. In Python heet ditcollision.propName
.- alleen de naam van de property is hier van belang: de waarde gebruiken we in dit geval niet.
- klik in de collision sensor de Tap button aan om maar 1 trigger te geven bij aanraking van de tafel of kast.
Het is niet erg als je er zelf nog niet helemaal uit bent gekomen. Juist als het niet werkt zoals je wilt leer je hier meer van doordat je de verkeerde code moet herstellen. Wanneer je er niet uit komt kun je naar onderstaande uitwerking kijken:
import bge
cont = bge.logic.getCurrentController()
start = cont.sensors["Start"]
collision = cont.sensors["AtTarget"]
steering = cont.actuators["Steering"]
def main():
collision.propName = "Shelf"
steering.target = "Shelf_8"
cont.activate(steering)
def handleCollision():
if collision.propName == "Shelf":
steering.target = "Desk_11"
collision.propName = "Desk"
else:
steering.target = "Shelf_8"
collision.propName = "Shelf"
cont.activate(steering)
if start.positive:
print("Initialize")
main()
elif collision.positive:
print("Collision")
handleCollision()
else:
print("No action")
Opmerkingen:
- we gebruiken de ENTER key om Morsy in beweging te zetten. Hiervoor gebruiken we een aparte functie
initialize()
. - als Morse direct van start gaat, zonder dat je de ENTER key gebruikt hebt, kan er sprake zijn van een collision-event: als de collision-sensor geen Property heeft (in Python:
propName == ""
), dan detecteert deze sensor een collision met elk willekeurig object - dus ook met het desk waar deze naast staat. Je kunt dit voorkomen door in het sensor-venster een willekeurige string als Property in te vullen - bijvoorbeeld "x".- Ga na in de logfile of er al direct sprake is van een collision.
- we hebben een aantal print-statements toegevoegd om in de logfile na te gaan wat er gebeurt. Kijk of je de logfile begrijpt. (Het script wordt ook uitgevoerd bij de "negative" overgangen van de sensoren).
Voor hulp zie: https://www.youtube.com/watch?v=y36ZGsFDA2E
Variaties:
- Hoe kun je Morsy direct van start laten gaan in de play modus, zonder de ENTER key te gebruiken?
- In deze uitwerking gebruiken we één controller, met één script, met twee sensoren. We moeten in het script dan uitzoeken met welk sensor-event we te maken hebben. Je kunt ook aparte controllers gebruiken voor het opstarten, en voor het afhandelen van een collision. Je gebruikt dan ook twee scripts. Probeer dit uit.
plus: visualiseer pakket https://www.youtube.com/watch?v=wJYlWa5D0hc