- 3 Minutes to read
App Structure
- 3 Minutes to read
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:
doc | Documentation. |
dat | Persistent data that the application stores during its execution. |
log | Internal logging of the application. |
res | Additional resources (ML models, images, sound files, etc.). |
src | Python source code. |
Files:
manifest.json | Application manifest. |
exec_settings.json | Internal execution information (simulator, robot ID, etc.). It should NOT be modified manually. |
__main__.py | Python entry point. It should NOT be modified manually. |
app.py | Application 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()')
TheRayaApplicationBase
embeds 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:
Exception | Condition |
---|---|
RayaApplicationException | The application could not be initialized. |
RayaInvalidAppNameException | Provided application name is not valid. |
RayaRestfulModeException | The 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.