../_images/tiago-icon.png ../_images/tiagopro-icon.png ../_images/ari-icon.png

Tutorial: Creating expressions with LEDs#

🏁 Goal of this tutorial

By the end of this tutorial, you will know how to request different type of LEDs effects using the LEDs devices available on PAL’s robots. Additionally, you will see an example of how PAL’s robots’s LEDs can be used for expressiveness purposes.

Pre-requisites#

  • This tutorial requires you to have python3 installed.

  • This tutorial requires you to have ROS noetic installed. If you don’t, follow these installation instructions. We suggest to choose the desktop-full version, to have access to ROS visualisation tools (e.g., rviz).

  • This tutorial requires you to have the pal_msgs package installed. You can download it from this GitHub repository.

  • This tutorial requires you to have a general knowledge of the PAL’s robots’s LEDs API. If you want to know more about the PAL’s robots’s LEDs API, check leds_api.

The code#

This is a possible implementation of a ROS node executing a demo to showcase how we can also use PAL’s robots’s LEDs devices to enhance its expressiveness.

ari_leds.py#
  1#!/usr/bin/env python3
  2
  3# -*- coding: utf-8 -*-
  4
  5import rospy
  6from actionlib import SimpleActionClient
  7from pal_device_msgs.msg import DoTimedLedEffectAction,\
  8 DoTimedLedEffectGoal, LedEffectParams
  9from pal_interaction_msgs.msg import TtsAction, TtsGoal
 10from std_msgs.msg import String
 11import numpy as np
 12
 13# led devices ids
 14BACK = 0
 15LEFT_EAR = 1
 16RIGHT_EAR = 2
 17RESPEAKER = 4
 18
 19MAX_PRIORITY = 255  # The maximum value for leds effect priority
 20
 21def init_clients():
 22    """ Initializing the action clients. """
 23
 24    # Creating a client object to communicate
 25    # with the LEDs action server
 26    led_client = SimpleActionClient("/pal_led_manager/do_effect",
 27                                DoTimedLedEffectAction)
 28    led_client.wait_for_server()
 29
 30    # Creating a client object to communicate
 31    # with the TTS action server
 32    tts_client = SimpleActionClient('/tts',
 33                                    TtsAction)
 34    tts_client.wait_for_server()
 35
 36    return led_client, tts_client
 37
 38
 39def set_color_progress_effect(goal,
 40                              r1,
 41                              g1,
 42                              b1,
 43                              a1,
 44                              r2,
 45                              g2,
 46                              b2,
 47                              a2,
 48                              percentage,
 49                              offset):
 50    """ A function to set a led effect
 51        to communicate the progress status
 52        regarding a task/action.
 53    """
 54
 55    # first_color --> completion colour
 56    goal.params.progress.first_color.r = r1
 57    goal.params.progress.first_color.g = g1
 58    goal.params.progress.first_color.b = b1
 59    goal.params.progress.first_color.a = a1
 60
 61    # second_color --> non-completed portion colour
 62    goal.params.progress.second_color.r = r2
 63    goal.params.progress.second_color.g = g2
 64    goal.params.progress.second_color.b = b2
 65    goal.params.progress.second_color.a = a2
 66
 67    # percentage --> percentage of LEDs coloured
 68    # in first_color
 69    goal.params.progress.percentage = percentage
 70
 71    # led_offset --> the led to start from
 72    # in a leds array
 73    goal.params.progress.led_offset = offset
 74
 75    return goal
 76
 77
 78def show_progress(client,
 79                  devices):
 80    """ Displaying a generic task completion
 81        progress via leds.
 82        This is a demo function to showcase the
 83        leds progress effect.
 84    """
 85
 86    goal = DoTimedLedEffectGoal()  # The object representing the led effect
 87    goal.devices = devices  # The devices performing the effect
 88    goal.params.effectType = LedEffectParams.PROGRESS  # The type of effect
 89
 90    # Setting values for the two progress
 91    # color components
 92    # first color --> complete
 93    # second color --> uncomplete
 94
 95    first_color_red = 0.0
 96    first_color_green = 0.0
 97    first_color_blue = 1.0
 98    first_color_alpha = 1.0
 99
100    second_color_red = 1.0
101    second_color_green = 0.0
102    second_color_blue = 0.0
103    second_color_alpha = 1.0
104
105    # led offset set to 0. Progression
106    # will be displayed starting from
107    # the top led, counterclockwise
108    offset = 0
109
110    # Incrementing the advancement with a 1% step
111    # every 0.2 seconds.
112    for percentage in np.arange(0, 1.01, 0.01):
113        goal = set_color_progress_effect(goal,
114                                         first_color_red,
115                                         first_color_green,
116                                         first_color_blue,
117                                         first_color_alpha,
118                                         second_color_red,
119                                         second_color_green,
120                                         second_color_blue,
121                                         second_color_alpha,
122                                         percentage,
123                                         offset)
124
125        # Setting non effect-specific parameters
126        goal.effectDuration.secs = 0
127        goal.effectDuration.nsecs = 200000000
128        goal.priority = MAX_PRIORITY
129
130        client.send_goal(goal)
131
132        # Printing the completion status
133        completion_str = str(percentage*100)+"%"
134        rospy.loginfo("Task completion: "+completion_str)
135
136        # Sleeping slightly less then the effect duration
137        # to always have the next completion goal
138        # queuing when the previous one execution finishes
139        rospy.sleep(0.19)
140
141
142def show_rainbow(client,
143                 devices,
144                 transition_duration,
145                 duration_secs,
146                 duration_nsecs = 0):
147    """ Setting up and seding a LedEffectGoal for
148        a rainbow effect (that is, continous transition
149        over the rainbow colours).
150    """
151
152    goal = DoTimedLedEffectGoal()
153    goal.devices = devices
154    goal.params.effectType = LedEffectParams.RAINBOW
155
156    # transition_duration --> the time the effect
157    # will take to complete an iteration over
158    # the rainbow colours
159    goal.params.rainbow.transition_duration.secs = transition_duration
160
161    # Setting non effect-specific parameters: time and priority
162    goal.effectDuration.secs = duration_secs
163    goal.effectDuration.nsecs = duration_nsecs
164    goal.priority = MAX_PRIORITY
165
166    client.send_goal_and_wait(goal)
167
168
169def show_fixed_color(client,
170                     devices,
171                     r,
172                     g,
173                     b,
174                     a,
175                     duration_secs,
176                     duration_nsecs = 0):
177    """ Setting up and sending a LedEffectGoal
178        for a fixed color leds effect
179    """
180
181    goal = DoTimedLedEffectGoal()
182    goal.devices = devices
183    goal.params.effectType = LedEffectParams.FIXED_COLOR
184
185    # Setting the colour parameters
186    goal.params.fixed_color.color.r = r
187    goal.params.fixed_color.color.g = g
188    goal.params.fixed_color.color.b = b
189    goal.params.fixed_color.color.a = a
190
191    # Setting non effect-specific parameters
192    goal.effectDuration.secs = duration_secs
193    goal.effectDuration.nsecs = duration_nsecs
194    goal.priority = MAX_PRIORITY
195
196    client.send_goal_and_wait(goal)
197
198
199def show_blinking_color(client,
200                        devices,
201                        r1,
202                        g1,
203                        b1,
204                        a1,
205                        duration_secs1,
206                        duration_nsecs1,
207                        r2,
208                        g2,
209                        b2,
210                        a2,
211                        duration_secs2,
212                        duration_nsecs2,
213                        duration_secs,
214                        duration_nsecs = 0):
215    """ Setting up and sending a LedEffectGoal
216        for a blinking color leds effect.
217        It alternates two colors with custom
218        temporisation.
219    """
220
221    goal = DoTimedLedEffectGoal()
222    goal.devices = devices
223    goal.params.effectType = LedEffectParams.BLINK
224
225    # Setting the first colour parameters
226    goal.params.blink.first_color.r = r1
227    goal.params.blink.first_color.g = g1
228    goal.params.blink.first_color.b = b1
229    goal.params.blink.first_color.a = a1
230
231    # Setting the first colour duration
232    goal.params.blink.first_color_duration.secs = duration_secs1
233    goal.params.blink.first_color_duration.nsecs = duration_nsecs1
234
235    # Setting the second colour parameters
236    goal.params.blink.second_color.r = r2
237    goal.params.blink.second_color.g = g2
238    goal.params.blink.second_color.b = b2
239    goal.params.blink.second_color.a = a1
240
241    # Setting the second colour duration
242    goal.params.blink.second_color_duration.secs = duration_secs2
243    goal.params.blink.second_color_duration.nsecs = duration_nsecs2
244
245    # Setting non effect-specific parameters
246    goal.effectDuration.secs = duration_secs
247    goal.effectDuration.nsecs = duration_nsecs
248    goal.priority = MAX_PRIORITY
249
250    client.send_goal_and_wait(goal)
251
252def send_tts(client,
253             text,
254             language = "en_GB",
255             blocking = False):
256    """ Function sending text to be pronounced
257        to the tts action server.
258        If blocking is True, the function
259        waits for answer from the action,
260        blocking the process.
261    """
262
263    goal = TtsGoal()
264
265    goal.rawtext.text = text
266    goal.rawtext.lang_id = "en_GB"
267
268    if blocking:
269        client.send_goal_and_wait(goal)
270    else:
271        client.send_goal(goal)
272
273
274if __name__ == '__main__':
275    try:
276        rospy.init_node('expressive_leds')
277
278        led_client, tts_client = init_clients()
279
280        # Requesting ARI to introduce people to the tutorial.
281        send_tts(tts_client,
282                 "Welcome to the expressive leds tutorial!",
283                 blocking = True)
284
285        # ARI is telling people that it will start downloading some
286        # "very important files". During the download process, it will
287        # show the progression status using the leds on its back
288        send_tts(tts_client,
289                 "I will now start loading some very important files!\
290                 Check my back leds to see what is the progression status.",
291                 blocking = True)
292        show_progress(led_client,
293                      [BACK])
294
295        # At this point, ARI has completed downloading the "very important
296        # files". To show how happy it is, ARI will emit a rainbow with
297        # all of its (available) leds
298        send_tts(tts_client,
299                 "Yes, I made it! Task completed!")
300        rospy.loginfo("yes, I made it! Task completed! :)")
301        show_rainbow(led_client,
302                     [BACK, LEFT_EAR, RIGHT_EAR],
303                     1,
304                     10)
305
306        # Something might be wrong with the files ARI downloaded!
307        # Being in an alert status, it sets all of its leds to red
308        rospy.loginfo("OH NO! Something is going wrong!")
309        send_tts(tts_client,
310                 "Oh no! Something might be wrong with these files!")
311        show_fixed_color(led_client,
312                         [BACK, LEFT_EAR, RIGHT_EAR, RESPEAKER],
313                         r=1,
314                         g=0,
315                         b=0,
316                         a=1,
317                         duration_secs=10)
318
319        # ARI is now sure that the downloaded files were not the right
320        # ones, and needs an expert help to revert the situation.
321        # ARI is now emitting blinking yellow light, to attract someone's
322        # attention
323        rospy.loginfo("Please, help me!"+\
324                       "These were not the very important files I needed!")
325        send_tts(tts_client,
326                 "Please, help me!\
327                  These were not the very important files I needed!")
328        show_blinking_color(led_client,
329                            [BACK, LEFT_EAR, RIGHT_EAR],
330                            r1=1,
331                            g1=0,
332                            b1=0,
333                            a1=1,
334                            duration_secs1=1,
335                            duration_nsecs1=0,
336                            r2=1,
337                            g2=1,
338                            b2=0,
339                            a2=1,
340                            duration_secs2=1,
341                            duration_nsecs2=0,
342                            duration_nsecs=200000000,
343                            duration_secs=20
344                            )
345    except rospy.ROSInterruptException:
346        print("Abruptly finished!")

The code explained#

First things first, we need to import the required packages.

ari-leds.py#
 5import rospy
 6from actionlib import SimpleActionClient
 7from pal_device_msgs.msg import DoTimedLedEffectAction,\
 8 DoTimedLedEffectGoal, LedEffectParams
 9from pal_interaction_msgs.msg import TtsAction, TtsGoal
10from std_msgs.msg import String
11import numpy as np

Then, we define some constant values used later in the code. This step increases code readability.

ari_leds.py#
13# led devices ids
14BACK = 0
15LEFT_EAR = 1
16RIGHT_EAR = 2
17RESPEAKER = 4
18
19MAX_PRIORITY = 255  # The maximum value for leds effect priority

Now, we are defining a set of functions that will be used later, in __main__. The first function we implement is init_clients(), to initialise the client-server connection required to interact with the ROS action servers involved in the LEDs and TTS management.

ari_leds.py#
21def init_clients():
22    """ Initializing the action clients. """
23
24    # Creating a client object to communicate
25    # with the LEDs action server
26    led_client = SimpleActionClient("/pal_led_manager/do_effect",
27                                DoTimedLedEffectAction)
28    led_client.wait_for_server()
29
30    # Creating a client object to communicate
31    # with the TTS action server
32    tts_client = SimpleActionClient('/tts',
33                                    TtsAction)
34    tts_client.wait_for_server()
35
36    return led_client, tts_client

We will now go through the definition of a set of functions to initialise and set the fields of a DoTimedLedEffectAction object, that is, the object sent by the node to the action server to request a specific LEDs effect. We invite you to check the message structure before going through the next functions definition, to have a better understanding of the fields involved in the LEDs effects requests.

We will start implementing a function for the progression effect. This is meant to showcase a generic progression state: for instance, the battery level while the robot is docked.

ari_leds.py#
39def set_color_progress_effect(goal,
40                              r1,
41                              g1,
42                              b1,
43                              a1,
44                              r2,
45                              g2,
46                              b2,
47                              a2,
48                              percentage,
49                              offset):

Let’s understand the function parameters in detail:

  • goal is the DoTimedLedEffectAction object which parameters will be set through the function.

  • r1, g1, b1, a1 are the red, green, blue and alpha parameters for the completion colour.

  • r2, g2, b2, a2 are the red, green, blue and alpha parameters for the complementary colour. The complementary colour will be used by those LEDs not using the completion colour.

  • percentage represents the fraction of lights to set with the completion colour. In a process advancement fashion, it represents the process completion status.

  • offset represents from which light in the LEDs array the progression should start from.

Once inside the function, we assign the colour parameters to the relative goal fields.

ari_leds.py#
56goal.params.progress.first_color.r = r1
57goal.params.progress.first_color.g = g1
58goal.params.progress.first_color.b = b1
59goal.params.progress.first_color.a = a1
60
61goal.params.progress.second_color.r = r2
62goal.params.progress.second_color.g = g2
63goal.params.progress.second_color.b = b2
64goal.params.progress.second_color.a = a2

Then we set the percentage:

ari_leds.py#
69goal.params.progress.percentage = percentage

And the light offset.

ari_leds.py#
73goal.params.progress.led_offset = offset

The function ends up returning the goal object.

ari_leds.py#
75return goal

Another function, show_progress, uses set_color_progress_effect. This is a demo function, simulating the advancement of the status of a generic process from 0% to 100%, advancing by a 1% step every 0.2 seconds.

ari_leds.py#
78def show_progress(client,
79                  devices)

This function requires two parameters:

  • client, the object used to manage the client-server communication with the robot’s LEDs action server.

  • devices, the list of LEDs devices that will perform the progression effect.

Initially, we create the goal object, setting two of its fields that will not change anymore: the type of effect and the device that will display the effect (in this case, the back LEDs).

ari_leds.py#
86goal = DoTimedLedEffectGoal()
87goal.devices = devices
88goal.params.effectType = LedEffectParams.PROGRESS

Then, we initialise the first and second colours parameters and the LEDs offset.

ari_leds.py#
 95first_color_red = 0.0
 96first_color_green = 0.0
 97first_color_blue = 1.0
 98first_color_alpha = 1.0
 99
100second_color_red = 1.0
101second_color_green = 0.0
102second_color_blue = 0.0
103second_color_alpha = 1.0
104
105# led offset set to 0. Progression
106# will be displayed starting from
107# the top led, counterclockwise
108offset = 0

At this point, the progression starts. To simulate a process status advancement, we iterate over an np.arange object. At each step, we set the goal parameters using the previously defined set_color_progress_effect.

ari_leds.py#
112for percentage in np.arange(0, 1.01, 0.01):
113    goal = set_color_progress_effect(goal,
114                                     first_color_red,
115                                     first_color_green,
116                                     first_color_blue,
117                                     first_color_alpha,
118                                     second_color_red,
119                                     second_color_green,
120                                     second_color_blue,
121                                     second_color_alpha,
122                                     percentage,
123                                     offset)

The last step missing before sending goal to the action server is setting the time duration and effect priority.

Warning

This being a demo, we will set the priority to the maximum possible value. We invite you to properly set the priority when using LEDs in your custom applications.

ari_leds.py#
126goal.effectDuration.secs = 0
127goal.effectDuration.nsecs = 200000000
128goal.priority = MAX_PRIORITY

At this point, we can send the goal object to the action server, using client.

ari_leds.py#
130client.send_goal(goal)

It’s useful printing the advancement status, for a qualitative evaluation of the effect execution.

ari_leds.py#
133completion_str = str(percentage*100)+"%"
134rospy.loginfo("Task completion: "+completion_str)

As a last step, we add an instruction blocking the process for 0.19 seconds, which is slightly less than the effect duration. This is required as blocking for the entire duration of the effect would introduce a small (but notable) time gap between two consecutive progression goals, where the LEDs would execute another effect from the effects queue (for instance, the battery level), presenting a fragmented behaviour.

Another effect we will be using during the tutorial is the rainbow effect. This makes the LEDs device change its colour continously, ranging over the whole rainbow colour spectrum. Let’s see how to implement a function to generate and request this effect.

ari_leds.py#
142def show_rainbow(client,
143                 devices,
144                 transition_duration,
145                 duration_secs,
146                 duration_nsecs = 0):

This function requires 5 parameters:

  • client is the object used to manage the client-server communication with the robot’s LEDs action server.

  • devices is the list of LEDs devices that will perform the effect.

  • transition_duration is the time the effect will take to complete an iteration over the rainbow colours.

  • duration_secs and duration_nsecs define the effect duration.

Firstly, we initialise the object representing the LEDs effect to be sent to the action server for execution.

ari_leds.py#
152goal = DoTimedLedEffectGoal()

Then, we set the devices that will execute the rainbow effect.

ari_leds.py#
153goal.devices = devices

As previously seen, we have to specify through the goal.params.effectType parameter which effect we want to use.

ari_leds.py#
154goal.params.effectType = LedEffectParams.RAINBOW

The rainbow effect has just one effect-specific parameter, the rainbow transition duration, that we can set through goal.params.rainbow.transition_duration.secs = transition_duration.

ari_leds.py#
159goal.params.rainbow.transition_duration.secs = transition_duration

The last step missing before sending goal to the action server is setting the time duration and effect priority.

Warning

This being a demo, we will set the priority to the maximum possible value. We invite you to properly set the priority when using LEDs in your custom applications.

ari_leds.py#
162goal.effectDuration.secs = duration_secs
163goal.effectDuration.nsecs = duration_nsecs
164goal.priority = MAX_PRIORITY

At this point, we can send the goal object to the action server, using client. The LEDs devices previously specified will execute the effect immediately if no other LEDs effect with MAX_PRIORITY is being performed; if this is not the case, then the effect will queue while waiting that all the previous queued effects with MAX_PRIORITY will have been performed.

ari_leds.py#
166client.send_goal(goal)

Another effect we will be using during the tutorial is the fixed-colour effect. This will set a static LEDs colour for a certain amount of time. Let’s see how we implemented a function to generate and request this effect.

ari_leds.py#
169def show_fixed_color(client,
170                     devices,
171                     r,
172                     g,
173                     b,
174                     a,
175                     duration_secs,
176                     duration_nsecs = 0)

This function requires 8 parameters:

  • client is the object used to manage the client-server communication with the robot’s LEDs action server

  • devices is the list of LEDs devices that will perform the effect.

  • r, g, b, a are respectively the red, green, blue and alpha parameters of the requested fixed colour.

  • duration_secs and duration_nsecs define the effect duration.

Firstly, we initialise the object representing the LEDs effect to be sent to the action server for execution.

ari_leds.py#
181goal = DoTimedLedEffectGoal()

Then, we set the devices that will execute the fixed-colour effect.

ari_leds.py#
182goal.devices = devices

As previously seen, we have to specify through the goal.params.effectType parameter which LEDs effect goal is meant for.

We set the fixed-colour red, green, blue and alpha parameters.

ari_leds.py#
186goal.params.fixed_color.color.r = r
187goal.params.fixed_color.color.g = g
188goal.params.fixed_color.color.b = b
189goal.params.fixed_color.color.a = a

The last step missing before sending goal to the action server is setting the time duration and effect priority.

Warning

This being a demo, we will set the priority to the maximum possible value. We invite you to properly set the priority when using LEDs in your custom applications.

ari_leds.py#
192goal.effectDuration.secs = duration_secs
193goal.effectDuration.nsecs = duration_nsecs
194goal.priority = MAX_PRIORITY

At this point, we can send the goal object to the action server, using client. The LEDs devices previously specified will execute the effect immediately if no other LEDs effect with MAX_PRIORITY is being performed; if this is not the case, then the effect will queue while waiting that all the previous queued effects with MAX_PRIORITY will have been performed.

ari_leds.py#
196client.send_goal(goal)

The last effect we will show through this tutorial is the blinking effect. This effects requires us to specify two colours and their duration; the LEDs executing this effect will alternate the two colours according to their duration. The effect will be performed for a specific effect duration, which is a parameter we have already seen through this tutorial. Let’s see how we implemented the function setting the parameters and sending the effect to the LEDs action server.

ari_leds.py#
199def show_blinking_color(client,
200                        devices,
201                        r1,
202                        g1,
203                        b1,
204                        a1,
205                        duration_secs1,
206                        duration_nsecs1,
207                        r2,
208                        g2,
209                        b2,
210                        a2,
211                        duration_secs2,
212                        duration_nsecs2,
213                        duration_secs,
214                        duration_nsecs = 0)

This function requires 16 parameters:

  • client is the object used to manage the client-server communication with the robot’s LEDs action server.

  • devices is the list of LEDs devices that will perform the effect.

  • r1, g1, b1, a1 are respectively the red, green, blue and alpha parameters of the first blinking colour.

  • duration_secs1 and duration_nsecs1 define the first colour duration.

  • r2, g2, b2, a2 are respectively the red, green, blue and alpha parameters of the second blinking colour.

  • duration_secs2 and duration_nsecs2 define the second colour duration.

  • duration_secs and duration_nsecs define the overall effect duration.

Firstly, we initialise the object representing the LEDs effect to be sent to the action server for execution.

ari_leds.py#
221goal  = DoTimedLedEffectGoal()

Then, we set the devices that will execute the blinking effect.

ari_leds.py#
222goal.devices = devices

As previously seen, we have to specify through the goal.params.effectType parameter which LEDs effect goal is meant for.

ari_leds.py#
223goal.params.effectType = LedEffectParams.BLINK

We can now start setting the effect-specific parameters. We initialise the first blinking colour red, green, blue and alpha values according to the function arguments.

ari_leds.py#
226goal.params.blink.first_color.r = r1
227goal.params.blink.first_color.g = g1
228goal.params.blink.first_color.b = b1
229goal.params.blink.first_color.a = a1

The blinking colours also require a duration.

ari_leds.py#
232goal.params.blink.first_color_duration.secs = duration_secs1
233goal.params.blink.first_color_duration.nsecs = duration_nsecs1

We repeat the same procedure for the second blinking colour.

ari_leds.py#
236goal.params.blink.second_color.r = r2
237goal.params.blink.second_color.g = g2
238goal.params.blink.second_color.b = b2
239goal.params.blink.second_color.a = a1
240
241# Setting the second colour duration
242goal.params.blink.second_color_duration.secs = duration_secs2
243goal.params.blink.second_color_duration.nsecs = duration_nsecs2

The last step missing before sending goal to the action server is setting the time duration and effect priority.

Warning

This being a demo, we will set the priority to the maximum possible value. We invite you to properly set the priority when using LEDs in your custom applications.

ari_leds.py#
246goal.effectDuration.secs = duration_secs
247goal.effectDuration.nsecs = duration_nsecs
248goal.priority = MAX_PRIORITY

At this point, we can send the goal object to the action server, using client. The LEDs devices previously specified will execute the effect immediately if no other LEDs effect with MAX_PRIORITY is being performed; if this is not the case, then the effect will queue while waiting that all the previous queued effects with MAX_PRIORITY will have been performed.

ari_leds.py#
250client.send_goal(goal)

Before checking the tutorial’s __main__, we will illustrate one more support function: send_tts. This will manage comunication with the robot’s TTS action server, sending it sentences that the robot should pronounce.

ari_leds.py#
252def send_tts(client,
253             text,
254             language = "en_GB",
255             blocking = False)

This function has 4 parameters:

  • client is the object used to manage the client-server communication with the robot’s TTS action server.

  • text is the requested sentence.

  • language is the language that the robot will use to pronounce the sentence.

  • blocking specifies whether the function execution should be blocking (that is, waiting for the action execution or failure) or not.

As we have already seen in other functions involving action servers, the first thing we do is initialising a goal. In this case, it will be a TtsGoal object.

ari_leds.py#
263goal = TtsGoal()

Then, we set the goal parameters related to the text to pronounce and the language to use.

ari_leds.py#
265goal.rawtext.text = text
266goal.rawtext.lang_id = "en_GB"

Now we are ready to send goal to the action server. The different function used for this depends on whether the blocking flag is set or not.

ari_leds.py#
268if blocking:
269    client.send_goal_and_wait(goal)
270else:
271    client.send_goal(goal)

At this point, we have defined all the functions required for this tutorial. In __main__, we can find an example of how the functions above might be used to enhance PAL’s robots’s expressivity.

First things first, we initialise the ROS node and the structures to communicate with the LEDs and TTS action servers:

ari_leds.py#
326if __name__=='__main__'
327    try:
328        # Initialising the ROS node
329        rospy.init_node('expressive_leds')
330
331        # Initialising the two action clients objects
332        # requested during the node execution
333        led_client, tts_client = init_clients()

We ask PAL’s robots to introduce who is watching to the tutorial. In this case, we are setting the blocking flag as we do not want PAL’s robots to proceed with any other tutorial-related operation as long as it has not finished the introduction.

ari_leds.py#
281send_tts(tts_client,
282         "Welcome to the expressive leds tutorial!",
283         blocking = True)

Now, the proper demo can start. The plot is:

  1. PAL’s robots starts downloading some very important files. During the process, PAL’s robots shows the progression status using the progress effect on the back LEDs.

  2. Once PAL’s robots finishes downloading the files, it will show how happy it is about it by executing the rainbow effect with the LEDs on the head and the back.

  3. Suddenly, PAL’s robots notices that something might be wrong with the very important files downloaded. The robot sets its LEDs to red using the fixed colour effect.

  4. It comes out that the very important files downloaded were not the right ones! PAL’s robots LEDs will start blinking using red and yellow, to attract someone’s attention as it needs help.

Let’s go step by step through the functions reproducing the storyline above. In step 1, we use the previously defined function show_progress for the LEDs effect, while using a blocking send_tts to introduce the dowloading operations.

ari_leds.py#
288send_tts(tts_client,
289         "I will now start loading some very important files!\
290         Check my back leds to see what is the progression status.",
291         blocking = True)
292show_progress(led_client,
293              [BACK])

In step 2, we send a non-blocking TTS request PAL’s robots is expressing how happy it is for having completed the previous process. To request the rainbow effect, we use the function specifically defined before.

ari_leds.py#
298send_tts(tts_client,
299         "Yes, I made it! Task completed!")
300rospy.loginfo("yes, I made it! Task completed! :)")
301show_rainbow(led_client,
302             [BACK, LEFT_EAR, RIGHT_EAR],
303             1,
304             10)

In step 3, we send a non-blocking TTS request and a fixed colour LEDs effect request to express concern regarding the downloaded files. The r, g, b, a parameters are such to display the red colour.

ari_leds.py#
308rospy.loginfo("OH NO! Something is going wrong!")
309send_tts(tts_client,
310         "Oh no! Something might be wrong with these files!")
311show_fixed_color(led_client,
312                 [BACK, LEFT_EAR, RIGHT_EAR, RESPEAKER],
313                 r=1,
314                 g=0,
315                 b=0,
316                 a=1,
317                 duration_secs=10)

In step 4, we send a non-blocking TTS request and we request a red-and-yellow blinking effect for PAL’s robots leds to attract people’s attention, as the robot needs help. The r1, g1, b1, a1 parameters are such to display the red colour. The r2, g2, b2, a2 parameters are such to display the yellow colour.

ari_leds.py#
323 rospy.loginfo("Please, help me!"+\
324               "These were not the very important files I needed!")
325send_tts(tts_client,
326         "Please, help me!\
327         These were not the very important files I needed!")
328show_blinking_color(led_client,
329                    [BACK, LEFT_EAR, RIGHT_EAR],
330                    r1=1,
331                    g1=0,
332                    b1=0,
333                    a1=1,
334                    duration_secs1=1,
335                    duration_nsecs1=0,
336                    r2=1,
337                    g2=1,
338                    b2=0,
339                    a2=1,
340                    duration_secs2=1,
341                    duration_nsecs2=0,
342                    duration_nsecs=200000000,
343                    duration_secs=20
344                    )

Next steps#

  • The node you have developed only includes some of the effects that PAL’s robots’s’ LEDs can perform. We invite you to explore more of these effects, playing with them for a deeper understanding of how LEDs can enhance the robot’s expressiveness.

  • If you want to know more about expressiveness in PAL’s robots, check Getting started with ARI - Combine voice, gesture and eyes.