Gallery Tour Guide App
  • 5 Minutes to read

Gallery Tour Guide App


Article Summary

In this tutorial, we are going to create a virtual ‘art gallery’ tour where the user can select which art painting they want to see and Gary accompanies them there. The app combines Gary’s interactive screen from our UI Kit and navigation skills.

The scene that we will use for this tutorial is the showroom scene.
Below you will find a practical code of the application and detailed explanation.

Before you start, if you have not done so already, it is recommended that you will read the Hello World app guide to familiarize yourself with the fundamentals of Ra-Ya applications:
Create your first app

Important note!

Remember that when using the UI Kit, before you run the application you need to open a browser with the following address; https://chest-web.web.app/app/{app_id} and replace {app_id} with your app_id.
For example, if the app id is "hello_world", the URL should be: https://chest-web.web.app/app/hello_world

App code

from raya.application_base import RayaApplicationBase
from raya.enumerations import THEME_TYPE
from raya.controllers.navigation_controller import POS_UNIT
 
MAP = 'unity_showroom'
 
SAVED_LOCATIONS = [
    {'id': 1, 'name':'Icy Road', 'x': -2.42, 'y':-11.89, 'angle':180},
    {'id': 2, 'name':'Starry Nebula', 'x': 2.76, 'y':-2.06, 'angle':0},
    {'id': 3, 'name':'Peaceful Coastline', 'x': 7.28, 'y':-13.73, 'angle':270},
]
 
class RayaApplication(RayaApplicationBase):
   
    async def setup(self):
        self.ui = await self.enable_controller('ui')
        self.nav = await self.enable_controller('navigation')
 
        await self.nav.set_map(MAP, wait_localization=True)
 
    async def loop(self):
 
        await self.ui.display_action_screen(title='Welcome to my gallery!',
            subtitle='Can I show you some art paintings?',
            button_text="Let's start",
            theme=THEME_TYPE.DARK)
 
        data = [{'id': 1, 'name': 'Icy Road', 'imgSrc': 'https://storage.googleapis.com/raya_files/Misc/Images/08.png'},
                {'id': 2, 'name': 'Starry Nebula', 'imgSrc': 'https://storage.googleapis.com/raya_files/Misc/Images/05.png'},
                {'id': 3, 'name': 'Peaceful Coastline', 'imgSrc': 'https://storage.googleapis.com/raya_files/Misc/Images/11.png'}]
 
        response = await self.ui.display_choice_selector(title='which art piece are you interested in?',
                                                        show_back_button=False,
                                                        data=data)
 
        selected_location = next(location for location in SAVED_LOCATIONS if location["id"] == response["selected_option"]["id"])
 
        await self.ui.display_screen(title='Navigating to ' + selected_location["name"], show_loader=True)
 
        await self.nav.navigate_to_position(x=selected_location["x"],y=selected_location["y"], angle=selected_location["angle"], pos_unit= POS_UNIT.METERS, wait=True)
 
        await self.ui.display_screen(title='We arrived!\nEnjoy this amazing piece of art', show_loader=False)
 
        await self.sleep(4)
   
    async def finish(self):
        pass

Analyizing the code

Constants

from raya.application_base import RayaApplicationBase
from raya.enumerations import THEME_TYPE
from raya.controllers.navigation_controller import POS_UNIT

Importing these libraries is necessary for the app to work as intended. Firstly, RayaApplicationBase is the library that provides the basic structure of a Ra-Ya application’s code. The THEME_TYPE and POS_UNIT enumerations are used to specify the graphical theme for the interactive screen and the unit of measure for navigation procedures, respectively.

MAP = 'unity_showroom'
 
SAVED_LOCATIONS = [
    {'id': 1, 'name':'Icy Road', 'x': -2.42, 'y':-11.89, 'angle':180},
    {'id': 2, 'name':'Starry Nebula', 'x': 2.76, 'y':-2.06, 'angle':0},
    {'id': 3, 'name':'Peaceful Coastline', 'x': 7.28, 'y':-13.73, 'angle':270},
]

The MAP constant specifies that this app is meant to work in the Showroom scene of the Unity simulator, as that is where the gallery is housed. SAVED_LOCATIONS contains the ID, name, and coordinates of each of the three paintings available for demonstration as part of the tour.

setup()

    async def setup(self):
        self.ui = await self.enable_controller('ui')
        self.nav = await self.enable_controller('navigation')

The setup() function is called at the beginning of any app execution in Ra-Ya application.
In this app, we’ll need Gary to navigate and interact with the user through the UI screen. Therefore, enabling the navigation and UI controllers grants us access to these functionalities.

        await self.nav.set_map(MAP, wait_localization=True)

In order for the navigation to work, Gary must first become localized. By setting the map to the predefined map name, “unity_showroom,” we make sure that the robot is able to navigate in the desired environment.

loop()

        await self.ui.display_action_screen(title='Welcome to my gallery!',
            subtitle='Can I show you some art paintings?',
            button_text="Let's start",
            theme=THEME_TYPE.DARK)

Here we are using a predefined screen from the UI kit called dispaly_action_screen.
The UI controller’s display_action_screen() function loads a screen with customizable options. For the purposes of this app, it should serve as a welcome screen to the tour with a button to press to start. This is achieved above by filling the title and subtitle fields with descriptive text, and adding a start button. This function call also uses the THEME_TYPE enumeration to set the screen to dark theme for style.

        data = [{'id': 1, 'name': 'Icy Road', 'imgSrc': 'https://storage.googleapis.com/raya_files/Misc/Images/08.png'},
                {'id': 2, 'name': 'Starry Nebula', 'imgSrc': 'https://storage.googleapis.com/raya_files/Misc/Images/05.png'},
                {'id': 3, 'name': 'Peaceful Coastline', 'imgSrc': 'https://storage.googleapis.com/raya_files/Misc/Images/11.png'}]

After pressing the ‘Let’s start’ button a screen with three options appears.
The tour has three artworks to choose from. In this segment, we define data as an array in which every element is a dictionary with data about each choice: the ID, name, and a URL to an image of the artwork.

For more information on the different screen types and how to format data for them, visit our UI controller section.

        response = await self.ui.display_choice_selector(title='which art piece are you interested in?',
                                                        show_back_button=False,
                                                        data=data)

The display_choice_selector() function takes in a title, an option to include a back button, and the choices’ data as formatted above. It automatically organizes the data to form three clickable buttons with the name and image of each artwork, and returns which choice was selected as a variable that we store in “response” in this case.

        selected_location = next(location for location in SAVED_LOCATIONS if location["id"] == response["selected_option"]["id"])
 
        await self.ui.display_screen(title='Navigating to ' + selected_location["name"], show_loader=True)
 
        await self.nav.navigate_to_position(x=selected_location["x"],y=selected_location["y"], angle=selected_location["angle"], pos_unit= POS_UNIT.METERS, wait=True)

Once the choice was selected, we access the data in response to figure out the next location. Then, we use the UI controller to display a message screen saying which artwork Gary is navigating to and use the navigation controller to navigate to the saved location of the selected artwork.

        await self.ui.display_screen(title='We arrived!\nEnjoy this amazing piece of art', show_loader=False)
 
        await self.sleep(4)

Once Gary arrives at the desired artwork, another message screen is displayed indicating the arrival. By calling the sleep() method with an argument of 4, we ensure that the program waits four seconds to let the user read the message before resetting the loop and asking where else to navigate to in the tour.

finish_app()

    async def finish(self):
        pass

This function is the place for disabling and closing any listeners, scanner and actions that might still be operating.
Since there were no listeners, cameras, or ongoing motions in the program, there is no need to disable or stop them, and the Ra-Ya application is finished.

It’s that simple!


Was this article helpful?