How to write an underworlds client¶
This guide explains how to build underworlds application in Python.
It assumes that underworld is installed (otherwise, check Installation).
First client: listing the nodes in a world¶
The following simple snippet of code is a good starting point for many
underworlds
Python applications:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | import logging; logger = logging.getLogger("underworlds.myapp")
import underworlds
# Define here the classes and functions you need
# ...
if __name__ == "__main__":
logging.basicConfig(level=logging.INFO)
# Manage command line options
import argparse
parser = argparse.ArgumentParser(description="My Cool App")
parser.add_argument("world", help="Underworlds world to monitor")
args = parser.parse_args()
with underworlds.Context("myapp") as ctx:
world = ctx.worlds[args.world]
# world.scene.nodes gives access to all the nodes present in this
# world
for node in world.scene.nodes:
# the 4x4 transformation matrix, relative to the parent
transformation = node.transformation
x,y,z = transformation[0:3, 3] # last column contains translation
print("Node %s (id: %s) is at (%.2fm, %.2fm, %.2fm) from \
its parent %s" % (node, node.id, x, y, z, node.parent))
# world.scene.rootnode is the root node of the scene
print("The root node is %s" % world.scene.rootnode)
print("It has %d children" % len(world.scene.rootnode.children))
|
Implementing a filter¶
Let see now one ‘real world’ example.
Filters are a common pattern in a underworlds-based system. We call a filter an application that monitors a world A, processes somehow its content, and generates a new world B which is a filtered version of A.
One possible example is a physics-based filter: such a filter would read the
positions of various objects from a ‘raw’ world fed by the sensors. Because
perception routines are usually slightly inaccurate, some objects may be
detected as if they were inside others, or on the contrary flying in the air,
above their support. Using a physics engine, a physics-based filter would
correct these misdetections, and place the objects at stable locations. This
would result in a new world that one could call stable world
. This new world
could then be used as input for further processing by other reasonners,
planners, etc.
A possible implementation of a simpler filter (that would simply get flying objects to ‘drop’ on their underlying support) could look like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | import logging; logger = logging.getLogger("underworlds.filter.flying")
import underworlds
from underworlds.types import *
from underworlds.helpers.geometry import transformed_aabb
def find_support(node, candidates):
# left as an exercise for the reader!
# (or check the link to the full source code below!)
def filter(in_scene, out_scene):
dynamic_objs = []
for node in in_scene.nodes:
if node.properties["physics"]:
dynamic_objs.append(node)
for obj in dynamic_objs:
support, dt = find_support(obj, in_scene.nodes)
if support:
logger.info("%s should be on %s. Moving its center at %.2fm" % (obj.name, support.name, dt))
# modify the position of the node in the 'out' world:
node = out_scene.nodes[obj.id]
node.transformation[2][3] = dt
out_scene.nodes.update(node) # commit the changes to the underworlds network
else:
print("No support for %s! Leaving it alone." % d.name)
if __name__ == "__main__":
# Manage command line options
import argparse
parser = argparse.ArgumentParser(description='Move flying objects to rest position'))
parser.add_argument("input", help="underworlds world to monitor")
parser.add_argument("output", help="resulting underworlds world")
args = parser.parse_args()
with underworlds.Context("flying filter") as ctx:
in_world = ctx.worlds[args.input]
setup_physics(in_world.scene)
out_world = ctx.worlds[args.output]
# Fill in the 'out' world by copying the 'in' world and running
# 'filter' a first time.
# copy the 'in' scene onto the 'out' scene, overwriting previous
# content
out_world.copy_from(in_world)
filter(in_world.scene, out_world.scene)
# then, monitor the 'in' world for changes and update accordingly
# the 'out' world.
try:
while True:
# wait until someting is modified in the world that
# we monitor
in_world.scene.waitforchanges()
# copy the 'in' scene onto the 'out' scene, overwriting previous
# content
out_world.copy_from(in_world)
filter(in_world.scene, out_world.scene)
except KeyboardInterrupt:
print("Bye bye")
|
You can see the complete source for this filter here: flying_filter.py