Table of Contents
Basic SIC Connector
Introduction
The Python API also provides its own concrete implementation of the AbstractSICConnector
class, called the BasicSICConnector
. It allows you to register callback functions for each action you send.
callback functions
called when the action is finished or a result becomes available
e.g.:
for device actions (e.g.:
wake_up
,say
orset_eye_color
), the callback function is called only oncefor touch events (e.g.
MiddleTactilTouched
), the callback function is called every time the event becomes availablethe result of vision operations (e.g.
on_face_recognized(identifier)
), the callback function is called every time the result becomes available
Example
import threading from social_interaction_cloud.basic_connector import BasicSICConnector from time import sleep class Example: def __init__(self, server_ip): self.sic = BasicSICConnector(server_ip) self.awake_lock = threading.Event() def run(self): # active Social Interaction Cloud connection self.sic.start() # set language to English self.sic.set_language('en-US') # stand up and wait until this action is done (whenever the callback function self.awake is called) self.sic.wake_up(self.awake) self.awake_lock.wait() # see https://docs.python.org/3/library/threading.html#event-objects self.sic.say_animated('You can tickle me by touching my head.') # Execute that_tickles call each time the middle tactile is touched self.sic.subscribe_touch_listener('MiddleTactilTouched', self.that_tickles) # You have 10 seconds to tickle the robot sleep(10) # Unsubscribe the listener if you don't need it anymore. self.sic.unsubscribe_touch_listener('MiddleTactilTouched') # Go to rest mode self.sic.rest() # close the Social Interaction Cloud connection self.sic.stop() def awake(self): """Callback function for wake_up action. Called only once. It lifts the lock, making the program continue from self.awake_lock.wait()""" self.awake_lock.set() def that_tickles(self): """Callback function for touch listener. Everytime the MiddleTactilTouched event is generated, this callback function is called, making the robot say 'That tickles!'""" self.sic.say_animated('That tickles!') example = Example('127.0.0.1') example.run()
In the example above:
A connected Nao robot will stand up, saying “You can tickle me by touching my head”
To wait until the Nao has finished standing up, the program is locked by the
self.awake_lock.wait()
statement.awake_lock
is an threading.Event() object, that blocks the main thread until the threading.Event() is set by callingself.awake_lock.set()
. This is done in theawake
callback function. This callback function is added to thewake_up
action.
Once the robot is finished standing up,
awake
is called, and the “lock is lifted”, allowing the program to continue.
For 10 seconds will say “that tickles” every time you touch the sensor on the middle of its head.
After 10 seconds, the Nao will sit down again.
A different callback function is that_tickles
. It is subscribed to the MiddleTactilTouched
event. Whenever the program is running, that_tickles
is called each time the middle head sensor is touched.
State Machines Interaction Flows
Implementing a social interaction flow will go more efficiently if your code could have a similar structure to a graph/flowchart. Each step in the interaction is going from one state to another, based on the input from an end-user and the goals of the robot.
To structure your code using state and state transitions you can use the state machine design pattern. See Gkasdrogkas (2020), Nath (2019) or Shalyto et al. for a more extensive explanation of what they are.
Using this approach you can create a whole chain of states, neatly separating each interaction step in different states and methods. It does not have to be a linear sequence. You can create branches and cycles, depending on the indented interaction flow.
The most important component of state machines are the state transitions.
define what triggers a transition (e.g.: a button press)
define prerequisites of a state transition (e.g.: to get from the sleep to the awake state, a robot first needs to stand up)
Usage
In order to facilitate the implementation of state machines, the library pytransitions ca be used. It is “a lightweight, object-oriented finite state machine implementation in Python with many extensions”. Read their guide to learn more.
Example
Let’s look at an example of how to use it together with the SIC Python API. The example is comprised of a basic interaction flow. In this interaction flow, the robot starts by being asleep, wakes up, introduces itself and gets acquainted with the person and then says goodbye.
It starts with creating a model class for a robot that has states and link it to a state machine:
from transitions import Machine class ExampleRobot(object): states = ['asleep', 'awake', 'introduced', 'got_acquainted', 'goodbye'] def __init__(self): self.machine = Machine(model=self, states=ExampleRobot.states, initial='asleep') self.machine.add_transition(trigger='start', source='asleep', dest='awake', before='wake_up', after='introduce') self.machine.add_transition(trigger='introduce', source='awake', dest='introduced', before='introduction', after='get_acquainted') ... def wake_up(self) -> None: self.sic.set_language('en-US') self.sic.wake_up() self.sic.run_loaded_actions() robot = ExampleRobot() robot.start() # causes state transition from asleep to awake
define all the states of the state machine (line 5)
initialise the state machine with the model, state and initial state (line 8)
add transitions between states (line 9) - if we have an instantiation of the
ExampleRobot
class we can now call thestart
method (trigger) to cause a transition from the initialasleep
state (source) the theawake
state (destination):the trigger to a transition is the method that causes the transition
in this case, the robot will wake up upon the call of the
start
method (line 21)
the source of a transition is the previous state in which the state machine was
in this case, “asleep”
the destination of a transition is the state to which the transition directs the state machine is directed
in this case, “awake”
before trigger of a transition is a statement to call a method before the transition happens
in this case, method
wake_up
(line 15)
after trigger of a transition is a statement to trigger after a transition happens
in this case, “introduce” becomes a trigger to the next transition “introduced” (line 11)
note: Often there are no external triggers to trigger a state transition in the human-robot interaction flow. For example, when the robot is awake and ready it should automatically move to a next state. Adding an
after
parameter to the next transition as a trigger would address this issue
For a complete working example see https://bitbucket.org/socialroboticshub/examples/src/main/python/4_state_machine.py .