Difference between revisions of "ElenaO-RV-proy1"

From robotica.unileon.es
Jump to: navigation, search
(Página nueva: == HOLA MUNDO (Versión 2.6) == El entorno de NaoQi es un framework distribuido y consta de 2 entidades principales: Módulos y proxies. Los módulos son objetos, que normalmente res...)
 
m
 
(54 intermediate revisions by 2 users not shown)
Line 1: Line 1:
== HOLA MUNDO (Versión 2.6) ==
+
* '''Author:'''  Elena Ortega Fernández
 +
* '''Email Addres:'''  elenaortega25@gmail.com
 +
* '''Academic Year:''' 2010-2011
 +
* '''Degree:''' Undergraduate
 +
* '''Tags:''' webots, naoqi, jmanager, player
 +
* '''Technologies:''' c, c++, naoqi, BICA
 +
* '''Status:''' Finished
 +
 
 +
 
 +
=Introducción al entorno NaoQI=
 +
 
 +
==Hola Mundo (Versión 2.6)==
  
 
El entorno de NaoQi es un framework distribuido y consta de 2 entidades principales: Módulos y proxies. Los módulos son objetos, que normalmente residirán en el robot y tienen asociados métodos que implementan determinada funcionalidad. De serie tenemos el módulo ALMotion que implementa multitud de movimientos en el robot, el módulo ALMemory que permite leer los sensores, el módulo ALTextToSpeech que nos permite usar el sintetizador de voz, etc.
 
El entorno de NaoQi es un framework distribuido y consta de 2 entidades principales: Módulos y proxies. Los módulos son objetos, que normalmente residirán en el robot y tienen asociados métodos que implementan determinada funcionalidad. De serie tenemos el módulo ALMotion que implementa multitud de movimientos en el robot, el módulo ALMemory que permite leer los sensores, el módulo ALTextToSpeech que nos permite usar el sintetizador de voz, etc.
Line 11: Line 22:
 
En el directorio ruta/aldebaran-sdk-v1.6.0-linux/modules/src/examples/ tenemos el ejemplo del hola mundo.
 
En el directorio ruta/aldebaran-sdk-v1.6.0-linux/modules/src/examples/ tenemos el ejemplo del hola mundo.
  
Primero tenemos que crear el build del proyecto
+
Antes de probar el ejemplo tenemos que establecer las variables de entorno de NaoQi
 +
 
 +
                $ export AL_DIR=<ruta>/aldebaran-sdk-v1.6.0-linux
 +
                $ export LD_LIBRARY_PATH=$AL_DIR/lib
 +
                $ export PATH=$AL_DIR/bin:$PATH
 +
                $ export PYTHONHOME=$AL_DIR
 +
                $ export PYTHONPATH=.:$AL_DIR/lib:$PYTHONPATH
 +
 
 +
Una vez que las tengamos, crearemos el build del proyecto
  
 
                 $ mkdir build
 
                 $ mkdir build
Line 45: Line 64:
 
''Nota'': test_allhelloword.py se encuentra en $AL_DIR/modules/src/examples. Y debemos modificar la dirección IP, por la de nuestro nao.
 
''Nota'': test_allhelloword.py se encuentra en $AL_DIR/modules/src/examples. Y debemos modificar la dirección IP, por la de nuestro nao.
  
----
+
==Creación de Modulos==
 +
 
 +
===Instalación de Paquetes===
 +
 
 +
Primero tenemos que instalar los módulos de Python: Cheetah y PyQt4. Para ello debemos instalar los paquetes:
 +
 
 +
                libqtgui4
 +
                python qt4
 +
                libgnuradio-qtgui0
 +
                libgnuradio-qtgui0-dev(**)
 +
                python-cheetah
 +
                python-mako
 +
       
 +
                cmake-curses-gui
 +
 
 +
Una vez que tengamos los paquetes instalados, si estan establecidas las variables de entorno de NaoQi, va a haber conflicto entre éstas y las de python. Para solucionar este conflicto deberemos comentar la AL_DIR, y eliminar las de python (PYTHONPATH, PYTHONHOME). Y establecer la PYTHONHOME:
 +
 
 +
                $ export PYTHONHOME=/usr/bin/python/:/usr/lib/python2.6/:/usr/lib/pymodules/python2.6/:
 +
 
 +
===Ejecución del Generador de Módulos===
 +
 
 +
Vamos al directorio de $AL_DIR/modules/src y desde allí lanzamos el generador
 +
 +
                $ python module_generator.py
 +
 
 +
Se podría hacer por consola de la siguiente forma
 +
 
 +
                $ python module_generator.py -p "nombre_proyecto" -a "autor" modulo1 modulo2...
 +
 
 +
 
 +
Nota: Una vez que esté el módulo creado, habría que volver a cambiarlas para compilar.
 +
 
 +
==Hola Mundo (Versión 2.6 con los módulos ALTextToSpeech y ALLogger)==
 +
 
 +
===Creación de los módulos===
 +
 
 +
El módulo ALTextToSpeech que nos permite usar el sintetizador de voz, mientras que el ALLogger nos permite crear mensajes Log.
 +
 
 +
Vamos a crear un módulo propio que encapsulará la funcionalidad del método Say en nuestro propio método. De esta manera crearemos tanto un módulo como un proxy.
 +
 
 +
Para la creación del módulo nos vamos a ayudar de la herramienta modulegenerator, que ya hemos visto, con la que generaremos un proyecto con un único módulo.
 +
 
 +
En el archivo modulo.cpp tenemos que definir la directiva ROBOT, de la siguiente forma:
 +
 
 +
                #define ROBOT
 +
 
 +
Además, al constructor le tenemos que añadir la descripción de nuestro módulo:
 +
 
 +
                functionName( "helloWorld", "testModule",  "Say the message Hello World" );
 +
                BIND_METHOD (modulo::helloWorld);
 +
 
 +
Una vez que tengamos ésto, añadimos la función init, que va a ser la encargada de crear tanto el proxy del ALLogger como el de ALTextToSpeech
 +
 
 +
                void modulo::init() {
 +
                  // Create a proxy to the logger module.
 +
                  // If this fails, we throw an exception and the module will not be registered.
 +
                  try {   
 +
                pLog = getParentBroker()->getLoggerProxy();
 +
                  } catch (const AL::ALError& e) {
 +
                    throw AL::ALError(getName(), "module()", "Fail to create a proxy to ALLogger "
 +
                      "module. Msg " + e.toString() + "\nModule will abort.");
 +
                  }
 +
                #ifdef ROBOT
 +
                  try {
 +
                this->pAudio = AL::ALPtr<AL::ALTextToSpeechProxy>(new AL::ALTextToSpeechProxy(getParentBroker()));
 +
                  } catch (const AL::ALError& e) {
 +
                    throw AL::ALError(getName(), "Module()", "Could not create a proxy to ALTextToSpeechProxy " +
 +
                      e.toString());
 +
                  }
 +
                #endif
 +
                this->pLog->info(getName(),"Todo ha salido OK *********************************");
 +
                }
 +
 
 +
Y por último (en el archivo modulo.cpp) añadimos nuestra función
 +
 
 +
                void modulo::helloWorld(){
 +
                std::string pmsg="Hello World";
 +
                #ifdef ROBOT
 +
                this->pAudio->callVoid("say", pmsg);
 +
                #endif
 +
                this->pLog->info(getName(),"Hello World");
 +
                }
 +
 
 +
 
 +
Ahora, nos vamos al archivo de cabecera (modulo.h) e incluimos en él las dos nuevas funciones dentro del constructor:
 +
 
 +
                void helloWorld();
 +
                void init();
 +
 
 +
Definimos e inicializamos como privados dos variables, una del tipo ALTextToSpeech y otra del tipo ALLogger, que van a realizar la función de proxy
 +
 
 +
                private:
 +
                  AL::ALPtr<AL::ALTextToSpeechProxy> pAudio;
 +
                  AL::ALPtr<AL::ALLoggerProxy> pLog;
 +
 
 +
===Compilación de los modulos y carga en el Nao===
 +
 
 +
La compilación y carga del módulo ya se ha explicado anteriormente y va a ser de la misma forma. Pero hay que asegurarse de que en el autoload.ini estén las bibliotecas necesarias para su ejecución, estas son:
 +
 
 +
                audiodevice
 +
                audioout
 +
 
 +
que tienen que ir en la etiqueta [core]
 +
 
 +
Además, en [extra] no tenemos que olvidarnos de añadir nuestro módulo.
 +
 
 +
===Creación de un Proxy Genérico===
 +
 
 +
También podemos utilizar los módulos de forma genérica, en vez de definir un proxy de un tipo concreto de módulo, lo definimos como un proxy genérico. Es decir, en lugar de definir un proxy de tipo ALTextToSpeech
 +
 
 +
                AL::ALPtr<AL::ALTextToSpeechProxy> pAudio;
 +
 
 +
lo definimos como ALProxy
 +
 
 +
                AL::ALPtr<AL::ALProxy> pAudio;
 +
 
 +
Por lo tanto, a la hora de crear el proxy, en vez de inicializarlo así
 +
 
 +
                this->pAudio = AL::ALPtr<AL::ALTextToSpeechProxy>(new AL::ALTextToSpeechProxy(getParentBroker()));
 +
 
 +
Lo inicializaremos de la siguiente forma
 +
 
 +
                pAudio = getParentBroker()->getProxy( "ALTextToSpeech" );
 +
 
 +
==Módulo ALMotion==
 +
 
 +
ALMotion es el módulo que proporciona a Nao los métodos necesarios para que éste se mueva.
 +
 
 +
Como con cualquier otro módulo, lo primero que tenemos que hacer a la hora de trabajar con él es crear un proxy de ALMotion.
 +
 
 +
                pMotion = getParentBroker()->getMotionProxy();
 +
 
 +
Una vez creado el proxy, podemos mandar cualquier comando a los motores de nao, pero éstos no se moveran, porque inicialmente la potencia en ellos es 0 (Stiffness). Por lo tanto, el siguiente paso necesario a la hora de trabajar con este módulo es establecer stiffness en el motor al que queramos dar potencia.
 +
Por ejemplo, si lo que queremos es que Nao ande, deberemos establecer Stiffness en ambas piernas
 +
 
 +
                pMotion->setStiffnesses ("RLeg",1.0);
 +
                pMotion->setStiffnesses ("LLeg",1.0);
 +
 
 +
Y a continuación ya podríamos mandarle el comando para andar
 +
 
 +
                pMotion->walkTo(0.2, 0.2, 1.5709)
 +
 
 +
El primer parámetro que le pasamos es '''x''' (distancia a lo largo del eje x en metros), el segundo '''y''' (distancia a lo largo del eje y en metros), y el tercero un '''ángulo''' (rotación sobre el eje z en radianes).
 +
 
 +
Si en vez de andar, quisiesemos que diese un sólo paso, se utilizaría el comando stepTo (que funciona de forma similar) con la diferencia que con este comando sólo da un paso. Por eso, si queremos que de dos pasos seguidos, deberemos indicarle que espere a que termine uno para empezar el otro con el comando wait, ya que sino, intentará hacerlo a la vez.
 +
Por ejemplo, en un movimiento de la cabeza, sería una interpolación de ambos movimientos (si intentamos moverlo de un punto '''x''' a un punto '''y''', y de un punto '''y''' a un punto '''z''', el resultado será un movimiento del punto '''x''' inicial al '''z''' final).
 +
 
 +
=BICA architecture=
 +
 
 +
BICA architecture (Robot Behaviour Based Architecture For Applications) is based on the activation of components using a tree. To see how to work with it, we will design a possible goalkeeper state machine:
 +
 
 +
[[Image:GoalKeeper.png]]
 +
 
 +
[[Image:iconos.png]]
 +
 
 +
Before starting to work with VICODE, we should know:
 +
 
 +
    - Orange icons are to create or delete a state.
 +
    - The small blue ones with a continuous line are to create new transition between states.
 +
    - The big blue ones with discontinuous line are to create a class dependency of a state.
 +
    - Arrows to join or remove the dependency of the states.
 +
 
 +
Moreover, to join the states with transitions or with state dependencies we must select the option and click on the start state and end.
 +
 
 +
Once we know this, we can already design the state machine.
 +
 
 +
When we save the state machine (.xml file), it automatically generates two files c + +, one with the source code and a header. In the source file, Bica generates the functions of the states and transitions, and a step function, to change from one state to another. Furthermore to instantiate the necessary classes in each state (Thus the dependencies of classes that we created).
 +
 
 +
The transition functions are Boolean functions whose condition is that to move from one state to another. In our example the condition of transition from initial state to SearchingBall state is not seen the ball, therefore, Initial2SearchingBall0 function should looks like:
 +
 
 +
    bool GoalKeeper::Initial2SearchingBall0_transition_code(void)
 +
    {
 +
      return !_BallDetector->seen();
 +
    }
 +
 
 +
We only add it the return statement.
 +
 
 +
 
 +
'''IMPORTANT NOTE:''' If we make some modification from Vicode, .cpp and .h files are overwritten, except the code that is between the auxcode comments or auxiliary functions created by us.
 +
   
 +
    //BUILDER COMMENT. DO NOT REMOVE. auxcode begin
 +
    //BUILDER COMMENT. DO NOT REMOVE. auxcode end
 +
 
 +
But be careful, '''''the whole step() function is overwritten. And if you modify something in these comments the whole files will be overwritten too.'''''
 +
 
 +
=Development of a goalkeeper=
 +
 
 +
The previous state machine, is a possible state machine for a goalkeeper, but not the one we are going to use. We will use it the following one:
 +
 
 +
[[Image:goalkeeper.jpg]]

Latest revision as of 10:47, 25 June 2014

  • Author: Elena Ortega Fernández
  • Email Addres: elenaortega25@gmail.com
  • Academic Year: 2010-2011
  • Degree: Undergraduate
  • Tags: webots, naoqi, jmanager, player
  • Technologies: c, c++, naoqi, BICA
  • Status: Finished


Introducción al entorno NaoQI

Hola Mundo (Versión 2.6)

El entorno de NaoQi es un framework distribuido y consta de 2 entidades principales: Módulos y proxies. Los módulos son objetos, que normalmente residirán en el robot y tienen asociados métodos que implementan determinada funcionalidad. De serie tenemos el módulo ALMotion que implementa multitud de movimientos en el robot, el módulo ALMemory que permite leer los sensores, el módulo ALTextToSpeech que nos permite usar el sintetizador de voz, etc.

Un módulo siempre forma parte de un broker o servidor que escucha en una determinada dirección IP y puerto (normalmente en la dirección IP del robot y puerto 9559).

La segunda entidad es el proxy. Un proxy es un cliente que se conecta a un determinado broker y ejecuta un método de uno de sus módulos. Los proxies o clientes normalmente se encuentran fuera del robot. Todos los ejemplos que hemos utilizado para probar el robot (dentro de la carpeta $AL_DIR/modules/src/examples/ son proxies, puesto que son clientes que se conectan al main broker o broker principal del NAO y ejecutan métodos de algunos de sus módulos (en concreto del módulo ALMotion).

También es habitual que alguno de los métodos que implementa un módulo haga de proxy. Es decir, que solicite la ejecución de un método de otro módulo.

En el directorio ruta/aldebaran-sdk-v1.6.0-linux/modules/src/examples/ tenemos el ejemplo del hola mundo.

Antes de probar el ejemplo tenemos que establecer las variables de entorno de NaoQi

               $ export AL_DIR=<ruta>/aldebaran-sdk-v1.6.0-linux
               $ export LD_LIBRARY_PATH=$AL_DIR/lib
               $ export PATH=$AL_DIR/bin:$PATH
               $ export PYTHONHOME=$AL_DIR
               $ export PYTHONPATH=.:$AL_DIR/lib:$PYTHONPATH

Una vez que las tengamos, crearemos el build del proyecto

               $ mkdir build
               $ cd build
               $ cmake -DCMAKE_TOOLCHAIN_FILE=$AL_DIR/ctc/toolchain-geode.cmake ..
               $ ccmake . (opcional)
               $ make

Copia la biblioteca dinámica al robot. En concreto deberás copiarla al directorio /home/nao/naoqi/lib/naoqi

               $ cd $AL_DIR/modules/src/examples/build/src/
               $ scp libtestbroker.so root@192.168.1.111:/home/nao/naoqi/lib/naoqi


Nuestro objetivo es que el robot, en el momento de arrancar, cargue nuestro módulo de manera automática de la misma manera que carga los módulos de Aldebarán. Para ello tendremos que editar el fichero /home/nao/naoqi/preferences/autoload.ini y añadir la siguiente línea:

               allhelloworld

Para ello deberemos conectarnos al robot

               ssh -l nao dir_ip

Ahora deberás reiniciar naoqi

               nao restart

Ahora, solo queda ejecutar el proxy

               python test_alhelloword.py


Nota: test_allhelloword.py se encuentra en $AL_DIR/modules/src/examples. Y debemos modificar la dirección IP, por la de nuestro nao.

Creación de Modulos

Instalación de Paquetes

Primero tenemos que instalar los módulos de Python: Cheetah y PyQt4. Para ello debemos instalar los paquetes:

                libqtgui4
                python qt4
                libgnuradio-qtgui0
                libgnuradio-qtgui0-dev(**)
                python-cheetah
                python-mako
        
                cmake-curses-gui

Una vez que tengamos los paquetes instalados, si estan establecidas las variables de entorno de NaoQi, va a haber conflicto entre éstas y las de python. Para solucionar este conflicto deberemos comentar la AL_DIR, y eliminar las de python (PYTHONPATH, PYTHONHOME). Y establecer la PYTHONHOME:

                $ export PYTHONHOME=/usr/bin/python/:/usr/lib/python2.6/:/usr/lib/pymodules/python2.6/:

Ejecución del Generador de Módulos

Vamos al directorio de $AL_DIR/modules/src y desde allí lanzamos el generador

                $ python module_generator.py

Se podría hacer por consola de la siguiente forma

                $ python module_generator.py -p "nombre_proyecto" -a "autor" modulo1 modulo2...


Nota: Una vez que esté el módulo creado, habría que volver a cambiarlas para compilar.

Hola Mundo (Versión 2.6 con los módulos ALTextToSpeech y ALLogger)

Creación de los módulos

El módulo ALTextToSpeech que nos permite usar el sintetizador de voz, mientras que el ALLogger nos permite crear mensajes Log.

Vamos a crear un módulo propio que encapsulará la funcionalidad del método Say en nuestro propio método. De esta manera crearemos tanto un módulo como un proxy.

Para la creación del módulo nos vamos a ayudar de la herramienta modulegenerator, que ya hemos visto, con la que generaremos un proyecto con un único módulo.

En el archivo modulo.cpp tenemos que definir la directiva ROBOT, de la siguiente forma:

                #define ROBOT

Además, al constructor le tenemos que añadir la descripción de nuestro módulo:

                functionName( "helloWorld", "testModule",  "Say the message Hello World" );
                BIND_METHOD (modulo::helloWorld);

Una vez que tengamos ésto, añadimos la función init, que va a ser la encargada de crear tanto el proxy del ALLogger como el de ALTextToSpeech

                void modulo::init() {
                  // Create a proxy to the logger module.
                  // If this fails, we throw an exception and the module will not be registered.
                  try {    
                	pLog = getParentBroker()->getLoggerProxy();
                  } catch (const AL::ALError& e) {
                    throw AL::ALError(getName(), "module()", "Fail to create a proxy to ALLogger "
                      "module. Msg " + e.toString() + "\nModule will abort.");
                  }
                #ifdef ROBOT
                  try {
                	this->pAudio = AL::ALPtr<AL::ALTextToSpeechProxy>(new AL::ALTextToSpeechProxy(getParentBroker()));
                  } catch (const AL::ALError& e) {
                    throw AL::ALError(getName(), "Module()", "Could not create a proxy to ALTextToSpeechProxy " +
                      e.toString());
                  }
                #endif 
                this->pLog->info(getName(),"Todo ha salido OK *********************************");
                }

Y por último (en el archivo modulo.cpp) añadimos nuestra función

                void modulo::helloWorld(){
                	std::string pmsg="Hello World";
                	#ifdef ROBOT
                		this->pAudio->callVoid("say", pmsg);
                	#endif	
                	this->pLog->info(getName(),"Hello World");
                }


Ahora, nos vamos al archivo de cabecera (modulo.h) e incluimos en él las dos nuevas funciones dentro del constructor:

                void helloWorld();
                void init();

Definimos e inicializamos como privados dos variables, una del tipo ALTextToSpeech y otra del tipo ALLogger, que van a realizar la función de proxy

                private:
                  AL::ALPtr<AL::ALTextToSpeechProxy> pAudio;
                  AL::ALPtr<AL::ALLoggerProxy> pLog;

Compilación de los modulos y carga en el Nao

La compilación y carga del módulo ya se ha explicado anteriormente y va a ser de la misma forma. Pero hay que asegurarse de que en el autoload.ini estén las bibliotecas necesarias para su ejecución, estas son:

                audiodevice
                audioout

que tienen que ir en la etiqueta [core]

Además, en [extra] no tenemos que olvidarnos de añadir nuestro módulo.

Creación de un Proxy Genérico

También podemos utilizar los módulos de forma genérica, en vez de definir un proxy de un tipo concreto de módulo, lo definimos como un proxy genérico. Es decir, en lugar de definir un proxy de tipo ALTextToSpeech

                AL::ALPtr<AL::ALTextToSpeechProxy> pAudio;

lo definimos como ALProxy

                AL::ALPtr<AL::ALProxy> pAudio;

Por lo tanto, a la hora de crear el proxy, en vez de inicializarlo así

                this->pAudio = AL::ALPtr<AL::ALTextToSpeechProxy>(new AL::ALTextToSpeechProxy(getParentBroker()));

Lo inicializaremos de la siguiente forma

                pAudio = getParentBroker()->getProxy( "ALTextToSpeech" );

Módulo ALMotion

ALMotion es el módulo que proporciona a Nao los métodos necesarios para que éste se mueva.

Como con cualquier otro módulo, lo primero que tenemos que hacer a la hora de trabajar con él es crear un proxy de ALMotion.

                pMotion = getParentBroker()->getMotionProxy();

Una vez creado el proxy, podemos mandar cualquier comando a los motores de nao, pero éstos no se moveran, porque inicialmente la potencia en ellos es 0 (Stiffness). Por lo tanto, el siguiente paso necesario a la hora de trabajar con este módulo es establecer stiffness en el motor al que queramos dar potencia. Por ejemplo, si lo que queremos es que Nao ande, deberemos establecer Stiffness en ambas piernas

                pMotion->setStiffnesses ("RLeg",1.0);
                pMotion->setStiffnesses ("LLeg",1.0);

Y a continuación ya podríamos mandarle el comando para andar

                pMotion->walkTo(0.2, 0.2, 1.5709)

El primer parámetro que le pasamos es x (distancia a lo largo del eje x en metros), el segundo y (distancia a lo largo del eje y en metros), y el tercero un ángulo (rotación sobre el eje z en radianes).

Si en vez de andar, quisiesemos que diese un sólo paso, se utilizaría el comando stepTo (que funciona de forma similar) con la diferencia que con este comando sólo da un paso. Por eso, si queremos que de dos pasos seguidos, deberemos indicarle que espere a que termine uno para empezar el otro con el comando wait, ya que sino, intentará hacerlo a la vez. Por ejemplo, en un movimiento de la cabeza, sería una interpolación de ambos movimientos (si intentamos moverlo de un punto x a un punto y, y de un punto y a un punto z, el resultado será un movimiento del punto x inicial al z final).

BICA architecture

BICA architecture (Robot Behaviour Based Architecture For Applications) is based on the activation of components using a tree. To see how to work with it, we will design a possible goalkeeper state machine:

GoalKeeper.png

Iconos.png

Before starting to work with VICODE, we should know:

   - Orange icons are to create or delete a state.
   - The small blue ones with a continuous line are to create new transition between states.
   - The big blue ones with discontinuous line are to create a class dependency of a state.
   - Arrows to join or remove the dependency of the states.

Moreover, to join the states with transitions or with state dependencies we must select the option and click on the start state and end.

Once we know this, we can already design the state machine.

When we save the state machine (.xml file), it automatically generates two files c + +, one with the source code and a header. In the source file, Bica generates the functions of the states and transitions, and a step function, to change from one state to another. Furthermore to instantiate the necessary classes in each state (Thus the dependencies of classes that we created).

The transition functions are Boolean functions whose condition is that to move from one state to another. In our example the condition of transition from initial state to SearchingBall state is not seen the ball, therefore, Initial2SearchingBall0 function should looks like:

   bool GoalKeeper::Initial2SearchingBall0_transition_code(void)
   {
      return !_BallDetector->seen();
   }

We only add it the return statement.


IMPORTANT NOTE: If we make some modification from Vicode, .cpp and .h files are overwritten, except the code that is between the auxcode comments or auxiliary functions created by us.

   //BUILDER COMMENT. DO NOT REMOVE. auxcode begin
   //BUILDER COMMENT. DO NOT REMOVE. auxcode end

But be careful, the whole step() function is overwritten. And if you modify something in these comments the whole files will be overwritten too.

Development of a goalkeeper

The previous state machine, is a possible state machine for a goalkeeper, but not the one we are going to use. We will use it the following one:

Goalkeeper.jpg