pyRobots: a toolkit for robot executive control¶
As you may well know if you ever tried to use them to implement under-specified, dynamic tasks, state machines are not always the most convenient tool to code robot controllers.
pyRobots
provides a set of Python decorators to easily turn standard
functions into background asynchronous tasks which can be pre-empted at
anytime and to make your controller resource-aware (no, a robot can not
turn left AND right at the same time).
It also provides an event-based mechanism to monitor specific conditions and asynchronously trigger actions.
It finally provides a library of tools to manage poses in a uniform way
(quaternions, Euler angles and 4D matrices, I look at you) and to interface
with existing middlewares (ROS, naoqi, aseba...). Note that pyRobots
is
not itself a robotic middleware.
pyRobots
is inspired by the URBI
language.
Main features¶
Turns any Python function into a background action with the decorator
@action
;Robot actions are non-blocking by default: they are instanciated as futures (lightweight threads);
Actions can be pre-empted (cancelled) at any time via signals (the
ActionCancelled
signal is raised):@action def safe_walk(robot): try: robot.walk() except ActionCancelled: robot.go_back_to_rest_pose() action = robot.safe_walk() time.sleep(1) action.cancel()
Create event with
robot.whenever(<condition>).do(<action>)
;Lock specific resources with a simple
@lock(...)
in front of the actions. When starting, actions will wait for resources to be available if needed:L_ARM = Resource() R_ARM = Resource() ARMS = CompoundResource(L_ARM, R_ARM) @action @lock(ARMS) def lift_box(robot): #... @action @lock(L_ARM) def wave_hand(robot): #... @action @lock(L_ARM, wait=False) def scratch_head(robot): #... robot.lift_box() robot.wave_hand() # waits until lift_box is over robot.scratch_head() # skipped if lift_box or # wave_hand are still running
Supports compound resources (like
WHEELS
==LEFTWHEEL
+RIGHTWHEEL
);Poses are managed explicitely and can easily be transformed from one reference frame to another one (integrates with ROS TF when available);
Extensive logging support to debug and replay experiments.
Support for a particular robot only require to subclass GenericRobot
for this robot (and, obviously, to code the actions you want your robot to
perform).
Combined with a knowledge base, pyRobots
makes an interesting
starting point for a high-level cognitive controller for robots.
Code Documentation¶
The documentation is currently sparse. Please fill bug reports everytime you can not figure out a specific bit.
Main entry points¶
Full package documentation¶
Minimum Working Example¶
...that includes the creation of a specific robot
import time
from robots import GenericRobot
from robots.decorators import action, lock
from robots.resources import Resource
from robots.signals import ActionCancelled
# create a 'lockable' resource for our robot
WHEELS = Resource("wheels")
class MyRobot(GenericRobot):
def __init__(self):
super(MyRobot, self).__init__()
# create (and set) one element in the robot's state. Here a bumper.
self.state.my_bumper = False
# do whatever other initialization you need :-)
def send_goal(self, pose):
# move your robot using your favorite middleware
print("Starting to move towards %s" % pose)
def stop(self):
# stop your robot using your favorite middleware
print("Motion stopped")
def whatever_lowlevel_method_you_need(self):
pass
@lock(WHEELS)
@action
def move_forward(robot):
""" We write action in a simple imperative, blocking way.
"""
# the target pose: simply x += 1.0m in the robot's frame. pyRobots
# will handle the frames transformations as needed.
target = [1.0, 0., 0., "base_link"]
try:
robot.send_goal(target)
while(robot.pose.distance(robot.pose.myself(), target) > 0.1):
# robot.sleep is exactly like time.sleep, except it lets the pyrobots
# signals pass through.
robot.sleep(0.5)
print("Motion succeeded")
except ActionCancelled:
# if the action is cancelled, clean up your state
robot.stop()
with MyRobot() as robot:
# Turn on DEBUG logging.
# Shortcut for logging.getLogger("robots").setLevel(logging.DEBUG)
robot.debug()
robot.whenever("my_bumper", value = True).do(move_forward)
try:
while True:
time.sleep(0.5)
except KeyboardInterrupt:
pass