Logistieke Robots/les 3: verschil tussen versies

Uit Lab
Naar navigatie springen Naar zoeken springen
 
(59 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 ==
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 <code>Templates > Python> GameLogic Simple</code>. Je ziet nu de volgende code verschijnen:
<syntaxhighlight lang="Python" line>
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()
</syntaxhighlight>
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. 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.
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:
# <code>import bge</code>    - Het script importeert de module ‘bge’ en beschikt zo over alle gedefinieerde functies in de bge module.
# <code>def main():</code>    - definieert de functie main met de daarop volgende opdrachten.
# <code>main() </code>  - 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 <code>bge.logic.getCurrentController()</code>
* 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 <code>cont.sensors[“Start”]</code> en <code>cont.sensors[“AtTarget”]</code>
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:
<syntaxhighlight lang="Python">
import bge
cont = bge.logic.getCurrentController()
start = cont.sensors["Start"]
collision = cont.sensors["AtTarget"]
steering = cont.actuators["Steering"]
def main():
  # define function main…
main()
</syntaxhighlight>
*  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:
<syntaxhighlight lang="Python">
if start.positive
    main()
</syntaxhighlight>
(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 <code>TRUE</code> is)
* Zorg ervoor dat in de definitie van de functie <code>main() </code> de Steering actuator geactiveerd wordt en naar Shelf_8 toe gaat (de voorste kast). De code ziet er nu als volgt uit:
<syntaxhighlight lang="Python">
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()
</syntaxhighlight>
=== 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 <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:
<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

Logistieke Robots

Lessen

  1. Les 1
  2. Les 2
  3. Les 3
  4. Les 4
  5. Les 5
  6. Les 6
  7. Les 7
  8. Les 8

Software

Zie ook Regels en richtlijnen
Zie ook Artikelen bewerken

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.

Show Package contents

Open vervolgens het blender executable bestand via het openen van de volgende folders: Contents > MacOS > blender

Blender starten met terminal

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:

  1. Voeg aan Robot_11 (de voorste) een Always sensor toe.
  2. Maak een nieuw Python script aan:
    1. klik op de "+" onderin het Text Editor venster (naast de naam van het bestand).
    2. verander de naam van het bestand in "Text.py"
    3. typ in de Text Editor: print(“Hello”)
  3. Voeg aan Robot_11 een Python controller:
    Voeg Python controller toe
  4. Selecteer als script voor deze Python-controller: "Text.py"
  5. Link de controller met de sensor:
    Link sensor en controller
  6. 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 functie logic.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:

  1. import bge - Het script importeert de module ‘bge’ en beschikt zo over alle gedefinieerde functies in de bge module.
  2. def main(): - definieert de functie main met de daarop volgende opdrachten.
  3. 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:

  1. Verander de Always sensor in een Keyboard sensor met als Key de ENTER knop. Geef deze sensor de naam ‘Start’
  2. Voeg een Steering actuator toe. Laat deze de naam ‘Steering’ houden en over de –X as bewegen.
  3. 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”] en cont.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 voor Shelf_8 (bijvoorbeeld Shelf). Deze gebruik je in de collision-sensor, om alleen een collision met dit object te detecteren. In Python heet dit collision.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