App Structure
  • 3 Minutes to read

App Structure


Article Summary

Overview

When creating a new app, the first step will be using our SDK and run the following command:

rayasdk init --app-id "helloworld" --app-name "Hello World"

This command creates the application files structure that will be called Project from now on.


In the following section, we will go over the created folders and files and explain the purpose and usage of each of them.

1. Project structure

A Project has the following structure:

app_id
├── doc
│   ├── <application_documentation>.py
│   └── <additional_docs>.md
├── dat
│   └── <persistent_data>.dat
├── log
│   └── <application_logs>.log
├── res
│   └── <resources>.res
├── src
│   ├── app.py
│   ├── <custom_modules>.py
│   └── <custom_packages>.py
│       └── ...
├── __main__.py
├── exec_settings.json
└── manifest.json

Folders:

docDocumentation.
datPersistent data that the application stores during its execution.
logInternal logging of the application.
resAdditional resources (ML models, images, sound files, etc.).
srcPython source code.

Files:

manifest.jsonApplication manifest.
exec_settings.jsonInternal execution information (simulator, robot ID, etc.). It should NOT be modified manually.
__main__.pyPython entry point. It should NOT be modified manually.
app.pyApplication source code, see the next section.

2. app.py file and GaryApplication class

The file src/app.py include the main code of the Application.

from raya.application_base import RayaApplicationBase

class RayaApplication(RayaApplicationBase):
    async def setup(self):
        # Create local attributes and variables
        self.i = 0
        self.log.info(f'Hello from setup()')

    async def loop(self):
        # Loop
        self.i += 1
        self.log.info(f'Hello from loop(), i={self.i}')
        await self.sleep(0.2)
        if self.i>=10:
            self.finish_app()

    async def finish(self):
        # Finishing instructions
        self.log.warn(f'Hello from finish()')

TheRayaApplicationBaseembeds all the methods you need to access the robot, so it is all you must import:

from raya.application_base import RayaApplicationBase
...

The main application class must be calledRayaApplication,and it must inherit from the RayaApplicationBase class so that the entry point file can detect and run it:

...
class RayaApplication(RayaApplicationBase):
...

2.1. setup() method

The setup()method is called only once at the beginning of the execution, just after the application is connected to the robot and registered to have access to the hardware. This method should include:

  • Controllers creation (see the Controllers section).
  • Local variables initialization.
  • Third-party modules initialization.
  • Other routines must be executed once at the beginning of the application execution.

For instance:

...
    async def setup(self):
        # Controllers initialization
        self.arm = await self.enable_controller('motion')
        self.voice = await self.enable_controller('cameras')
        # Local variables initialization
        self.counter = 0
        self.target_place = 'kitchen'
        # Third-party modules initialization
        self.model = ml_library.load_model()
        self.optimizer = convex_lib.create_optimizer()
...

2.2. loop() method

The loop() method is repeatedly called until the end of the execution. This loop can be finished by calling the method finish_app(), or receiving an external termination signal.

This method should contain the main procedures to be executed by the robot during the application lifetime.

For instance:

...
    async def loop(self):and
        # Start arm trajectory and speaking
        self.arm.predef_trajectory('right_hand_waving')
        self.voice.text_to_speech('Hello everyone, my name is Gary')
        # Wait until arm trajectory and speaking finish
        await self.arm.await_while_moving()
        await self.voice.await_while_speaking()
        # finish application
        self.finish_app()
...

Async finish_app() method must be called (awaited) to finish the application in a controlled way. If it is not called, the loop method will be repeated until an external signal interrupts the application (managed by the App manager).

In the previous example, the loop executes only once. The schema could be changed to allow multiple executions of loop(), so other stuff can be executed while the robot is moving and speaking.

...
    async def loop(self):
        # running_flag was initialized as 'false' in setup()
        if not self.running_flag:
            # Start arm trajectory and speaking
            self.arm.predef_trajectory('right_hand_waving')
            self.voice.text_to_speech('Hello everyone, my name is Gary')
            self.running_flag = True
        else:
            # Wait until arm trajectory and speaking finish
            if not self.arm.is_moving() and not self.voice.is_speaking():
                self.finish_app()
        # Other stuff can be done while moving and speaking
...

2.3. finish() method

The finish() method is called at the end of the application execution, just before the disconnection with the robot hardware. This method is reached after a loop() execution in which self.finish_app() is called, or when a termination signal is sent from the App Manager.

This method should include:

  • Recovering the initial robot state.
  • Disconnection from third-party modules.

For instance:

...
    async def finish(self):
        # Recovery initial robot state
        self.arm.move_to('home')
        await self.arm.await_while_moving()
        # Disconnect from third-party modules
        self.model.close()
...

2.4. Application Exceptions

The application creation process can throw the following Python exceptions:

ExceptionCondition
RayaApplicationException    The application could not be initialized.
RayaInvalidAppNameExceptionProvided application name is not valid.
RayaRestfulModeExceptionThe restful mode could not be enabled.

See the Full List of Exceptions.


3. Programming Considerations

  • It is mandatory to define the three methods: setup(), loop() and, finish().
  • Functions and methods can not be empty (Python constraint), so if you do not need to add functionality to one of the required methods, just fill it with return None, or with pass.

4. Third-party libraries

Applications can import third-party modules and packages. Developers can create their own libraries and include them in the src folder. They can also use pip-available libraries and include them in the manifest.xml file.


Was this article helpful?

What's Next