-
Notifications
You must be signed in to change notification settings - Fork 1
06. Tutorial 6
In this tutorial, we introduce the keyword 'targeting'.
This keyword is used to set sensory motor loop during runtime (e.g. to have the robot walking toward a moving ball while looking at it).
This is the most powerful keyword of playful. But it is counter intuitive (you have been warned).
program:
virtual_balls_detection
targeting ball: ball_display
The node "virtual_balls_detection" pushes information about a blue and a green bouncing balls to playful's memory. For each ball, Playful spawns an instance of "ball_display", resulting in the display of all the balls (here the blue and the green).
To give an intuition where this is going at: Imagine you want the robot to always walk to the closest ball it detects, but you do not know in advance how many balls will be detected by the robot. Because of 'targeting', this could be implemented in a single command:
targeting ball: walk_to, priority of 1/distance
The code above sets the following:
- Everytime a new ball is detected at runtime, the playful engine spawns a new walk_to action.
- All the nodes and evaluations (here walk_to and distance) refer to this new ball instance (it 'targets' this specific ball), i.e. it sets a sensory motor loop between ball detection and update of walk configuration.
- At runtime, several instances of "walk_to" (one per detected ball) may exist, and compete for activation. The prioritization ensures the robot always walks toward the closest one (as continuously reevaluated).
Note that at startup, before the robot detects any ball, no "walk_to" action is instantiated.
In this tutorial we will see:
- how to define a scheme that can be targeted ('ball' here is called a 'scheme', using playful terminology).
- how to create nodes and evaluations that can be targeted by a new scheme instance.
- how to define what "new" means, as in "the robot was tracking a ball, turned its head and saw a new ball".
The playful code mentions a ball:
targeting ball: ball_display
Using playful terminology, "ball" is a scheme. A scheme is a collection of properties, in this case a position, a time stamp and a color. Related python code:
class position(playful.Property):
def fuse(self,value):
self._value=value
def similarity(self,value):
return None
class time_stamp(playful.Property):
def fuse(self,value):
self._value=value
def similarity(self,value):
return None
class color(playful.Property):
def fuse(self,value):
self._value=value
def similarity(self,value):
if self._value == value :
return True
return False
Playful properties, the building blocks of schemes, are just a value holder (self._value), and fuse and similarity functions. In short, these properties make the assumption here that there will be a unique ball for each color (only the similarity function of color returns True if the color value is identical).
Optional explanations: Fuse functions set how the property of a scheme should be updated based on new perception. Overriding the value as in this tutorial is typically ok. The similarity functions is used to evaluate the similarity between two schemes. The "None" value returned by the functions of position and time_stamp indicate these properties have no influence on the measurement of similarity. On the other hand, the similarity function of color indicates that two schemes of the same color correspond to the same scheme.The ball scheme is declared as a position, time_stamp and color in the file /playful_tutorial/play/schemes.play.
ball : scheme
position, time_stamp, color
It is trivial to create new properties and declare new types of scheme.
Our simulated robot does not have any real sensors, and for this tutorial we simply create a node which simulates the detections of bouncing balls
class virtual_balls_detection(playful.Node):
def execute(self):
# simulating bouncing balls in 1D
class _Position_manager:
def __init__(self,initial_position,speed,direction=1,max_x=30):
self.position = initial_position
self.speed = speed
self.direction = direction
self.max_x = max_x
def update(self):
self.position += self.direction * self.speed
if self.position > self.max_x :
self.position = self.max_x
self.direction = -1 * self.direction
if self.position < 0 :
self.position = 0
self.direction = -1 * self.direction
return self.position
time_start = time.time()
blue = _Position_manager(0,0.2)
green = _Position_manager(0,0.1)
#you may uncomment for fun
#red = _Position_manager(10,0.15)
while not self.should_pause():
t = time.time()
# creating a ball objects from properties, and sending it to the memory
# "fuse" means the memory compares the incoming scheme with schemes already
# maintained in the memory (similarity functions of the properties) and either maintain a new
# scheme or fuse with an existing scheme (fuse functions of the properties)
# the blue ball is created from start
playful.memory.fuse(playful.create("ball",position=blue.update(),time_stamp=t,color="BLUE"))
# the green ball is created 4 seconds after start
if(t-time_start > 4):
playful.memory.fuse(playful.create("ball",position=green.update(),time_stamp=t,color="GREEN"))
# uncomment for fun
#playful.memory.fuse(playful.create("ball",position=red.update(),time_stamp=t,color="RED"))
self.spin(20)
This leaf node simulates the perception by robot of virtual balls (in real applications, this could be a node using for example opencv over a video stream to detect balls, determining their color, computing their position, and pushing related ball schemes to the memory)
This node simulates:
- from the start, a blue ball is detected
- a green ball is detected 4s after this.
This node encodes info into a ball schemes that it pushes to the memory. The memory uses the similarity and fusing functions to update existing schemes and create new ones.
When running the tutorial, you may see the program expanding during runtime after 4 seconds : the targeting keyword (in the playful script) commands a new leaf node corresponding to the green ball to be created.
Also, feel free to uncomment code in the node to simulate a 3rd red ball, and notice the playful script does not need to be updated. The playful code is agnostic to the number of balls detected.
The python code simply read from the memory the value of the properties of the targeted scheme, and display it using Playful's console.
# class for displaying a ball in the console
# (note that the code is not specific to ball, though:
# it is specific to scheme with a color and position properties)
class ball_display(playful.Node):
def execute(self):
while not self.should_pause():
# the targeting keyword in the playful script associated this instance of
# 'ball_display' with one of the ball scheme. 'self.get_scheme_id()'
# returns the unique id of the ball scheme this instance is associated to,
# and the get_propery_value function allows to access the properties of this scheme.
position = playful.memory.get_property_value("position",scheme_id=self.get_scheme_id())
color = playful.memory.get_property_value("color",scheme_id=self.get_scheme_id())
if position and color :
playful.console(str(id(self))," "*int(position)+str(color))
self.spin(10)
Playful has been developed at the Max Planck Institute for Intelligent Systems, Tuebingen, Germany