Skip to content

00. Overview

Vincent Berenz edited this page Nov 12, 2018 · 17 revisions

This overview is there to give a rapid feeling on how Playful works. For examples of Playful code you can run, visit the tutorials

Parallel actions

Playful is a scripting language for specifying parallel running actions. For example, to get your robot to move the head and the arm at the same time:

move_head
move_arm

This has the two nodes 'move_head' and 'move_arm' running in parallel forever.

Python node

'move_head' and 'move_arm' must be declared using Python. For example:

class move_head (playful.node):
    
    def execute(self):

        while not self.should_pause():

             # using robot API to move head
             
             # working at 20 Hz
             self.spin(20)

Conditional activation

Nodes do not have to run all the time. Via the 'while' keyword, you may associate your node to any arbitrary python function. For example:

move_head, while happy
move_arm

This Playful script has the robot to move the head only when 'happy'. 'happy' must be declared using Python:

def happy():
     # any arbitrary code you want that returns either True or False
     return True

Playful's engine continuously evaluate 'happy'. When 'happy' returns True, 'move_head' activates, when 'happy' returns False, it deactivates.

Resource management and prioritization

Sometimes, two nodes should never run at the same time. That is typically the case for two nodes sending (conflicting) commands to the same robotic joints. For example, that could be catastrophic:

# catastrophic ?
head_yes
head_no

The code above activates simultaneously nodes for the head to make a 'yes' motion and a 'no' motion. Not good.

To solve this, Playful provides resource management, i.e. a tool for avoiding two nodes to ever send conflicting commands to the same joints. For example:

class head_yes (playful.Node):

    def execute(self):

        while not self.should_pause():

              # resource management
              if self.ask_for_resource("head"):
    
                 # here code that uses the robot API to move the head

              else:
         
                 self.release_resource("head")
          
              self.spin(20)

If the code for 'head_no' also asks for the resource, then 'head_yes' and 'head_no' will never run at the same time. But then, which one will run ? Playful provides the 'priority' keyword to solve this:

head_yes, priority of 2
head_no, priority of 1

2 is higher than 1, so 'head_yes' will run, and 'head_no' will not. But for more subtle prioritization, you may also associate 'priority' with any python function you want:

head_yes, priority of sin
head_no, priority of 1 

with sin being a python function, for example:

def sin():
    return abs( 2.0*math.sin(time.time()) )

This will have the robot alternating between saying yes and no with the head.

Feel free to mix

Of course, you may mix 'while' and 'priority' as you wish:

head_yes, while happy, priority of sin
head_no, priority of 1

State machines

If you prefer, you can also use state machines:

head_yes, switch to head_no if not happy
head_no, switch to head_yes if happy

Targeting

Often, nodes are not 'blind' action that do not need any sensory input. For example, 'look_at' would be a node which needs an object to look at. For example, it could be a ball:

ball_detection
targeting ball: look_at

or it could be a face:

face_detection
targeting face: look_at

Here 'ball_detection' (or 'face_detection') and 'look_at' run continuously in parallel. So, if the position of the ball continuously changes, the code above will implement a smooth head tracking. Here the related python code:

def ball_detection(playful.Node):

    def execute(self):

        while not self.should_pause():

             # here python code using robot API to determine 
             # position of ball in field of vision

             # encapsulating the position in a scheme
             # that is sent to the memory
             scheme = playful.create('ball',
                                     position=position,
                                     time_stamp=time.time())
             playful.memory.push(scheme)
             
             self.spin(20)


def look_at(playful.Node):

     def execute(self):
      
         while not self.should_pause():
         
              if self.ask_for_resource('head'):

                  # getting the position from the memory.
                  position = self.get_property('position')

                  # here python code using robot API
                  # to center field of vision at position
                  
              else :
        
                 self.release_resource('head')


              self.spin(20)

The 'targeting' keyword can be used also in relation with python functions. For example, to get the robot to look only at a ball when in the field of vision (and move the head randomly at other times):

targeting ball: look_at, while being_seen, priority of 2
random_head_motion, priority of 1
ball_detection

In the same way that 'look_at' refers to the position of the ball, 'being_seen' can be a python function that refers to the time stamp of the ball:

# returns True when the target has a new time stamp (i.e. is currently seen)
# and False when the time stamp of the target is old (i.e. has not been seen
# for a while).
def being_seen(scheme_id=None,threshold=0.2):

    current_time = time.time()
    detected_time = playful.memory.get_property_value(scheme_id,"time_stamp")
    delta_time = current_time-detected_time

    if delta_time < threshold:
          return True

    return False

Usage of 'targeting' makes sure the correct scheme_id (i.e. the unique identifier of the target, here the ball) is passed to the 'being_seen' function at run-time

Behavior tree

Playful node

So far, nodes corresponded exclusively to Python code. But node can also be written in Playful scripting language. Thus, you can create behavior tree of arbitrary depth. For example:

ball_search_and_look
move_arm

ball_search_and_look:
     targeting ball: look_at, while being_seen, priority of 2
     random_head_motion
     ball_detection

The node 'ball_search_and_look' is a Playful node, and here it runs in parallel with 'move_arm'.

Tree and targeting

Behavior tree and 'targeting' work well together:

targeting ball: look_and_point
ball_detection

look_and_point:
      look_at, while being_seen, priority of 2
      random_head_motion
      point_at, while being_seen # point the end effector toward targeted object

Information about the targeted object 'flows' into the 'look_and_point' branch ('look_at', 'point_at' and 'being_seen' all refer to the ball).

Code reusability

Declared Playful nodes can be reused, e.g. "look_and_point" in this script:

targeting ball: look_and_point, while being_seen, priority of 2
targeting face: look_and_point, priority of 1
ball_detection
face_detection

look_and_point:
      look_at, while being_seen, priority of 2
      random_head_motion
      point_at, while being_seen

This has the robot looking and pointing at a ball if currently seen, else looking at and pointing to a detected face. All in a dynamic and lively fashion.

Other features

And that is the gist of Playful. In the tutorials, you will also see how to pass arguments to the python code, how to manage environment with several objects of the same type (e.g. there are two balls !), how to create playful libraries that can be reused over projects, etc.