Skip to content

Commit 361d6bc

Browse files
committed
Merge pull request #64 from personalrobotics/feature/SmoothingRefactor
Trajectory execution refactor
2 parents 332a3e3 + afbadce commit 361d6bc

File tree

13 files changed

+1087
-502
lines changed

13 files changed

+1087
-502
lines changed

README.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,38 @@ resolve multiple objects in one statement:
303303
```
304304

305305

306+
## Concurrent Execution
307+
308+
PrPy has native support for [futures](http://en.wikipedia.org/wiki/Futures_and_promises) and
309+
[coroutines](http://en.wikipedia.org/wiki/Coroutine) to simplify concurrent programming. A
310+
_future_ encapsulates the execution of a long-running task. We use the concurrency primitives
311+
provided by the [`trollius` module](http://trollius.readthedocs.org/en/latest/using.html),
312+
which is a Python 2 backport of the [`asyncio` module](https://docs.python.org/3/library/asyncio.html)
313+
from Python 3.
314+
315+
We can use these primitives to parallelize planning and execution:
316+
317+
```python
318+
@coroutine
319+
def do_plan(robot):
320+
# Plan to goal1 and start executing the trajectory.
321+
path1 = yield From(robot.PlanToEndEffectorPose(goal1, execute=False))
322+
exec1_future = robot.ExecutePath(path1)
323+
324+
# Plan from goal1 to goal2.
325+
robot.SetDOFValues(GetLastWaypoint(path1))
326+
path2 = yield From(robot.PlanToEndEffectorPope(goal2, execute=False))
327+
328+
# Wait for path1 to finish executing, then execute path2.
329+
exec1 = yield From(exec1_future)
330+
exec2 = yield From(robot.ExecutePath(path2))
331+
332+
raise Return(path1, path2)
333+
334+
loop = trollius.get_event_loop()
335+
path = loop.run_until_complete(do_plan(robot))
336+
```
337+
306338
## Method Binding
307339

308340
Finally, PrPy offers helper functions for binding custom methods on (i.e.

src/prpy/base/manipulator.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ def _PlanWrapper(self, planning_method, args, kw_args):
153153
args, cloned_args)
154154

155155
# Strip inactive DOFs from the trajectory.
156-
config_spec = cloned_robot.GetActiveConfigurationSpecification()
156+
config_spec = cloned_robot.GetActiveConfigurationSpecification('linear')
157157
openravepy.planningutils.ConvertTrajectorySpecification(
158158
cloned_traj, config_spec
159159
)
@@ -164,6 +164,6 @@ def _PlanWrapper(self, planning_method, args, kw_args):
164164

165165
# Optionally execute the trajectory.
166166
if 'execute' not in kw_args or kw_args['execute']:
167-
return self.GetRobot().ExecuteTrajectory(traj, **kw_args)
167+
return self.GetRobot().ExecutePath(traj, **kw_args)
168168
else:
169169
return traj

src/prpy/base/mobilebase.py

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import copy, functools, numpy, openravepy
3232
from .. import bind
3333
from prpy.clone import Clone
34+
from ..planning.retimer import OpenRAVEAffineRetimer
3435

3536
def create_affine_trajectory(robot, poses):
3637
doft = openravepy.DOFAffine.X | openravepy.DOFAffine.Y | openravepy.DOFAffine.RotationAxis
@@ -50,6 +51,8 @@ def __init__(self, sim, robot):
5051
self.simulated = sim
5152
self.robot = robot
5253

54+
self.retimer = OpenRAVEAffineRetimer()
55+
5356
def __dir__(self):
5457
# Add planning methods to the tab-completion list.
5558
method_names = set(self.__dict__.keys())
@@ -167,6 +170,41 @@ def _BasePlanWrapper(self, planning_method, args, kw_args):
167170

168171
# Optionally execute the trajectory.
169172
if 'execute' not in kw_args or kw_args['execute']:
170-
return robot.ExecuteTrajectory(traj, **kw_args)
173+
return self.ExecuteBasePath(traj, **kw_args)
171174
else:
172175
return traj
176+
177+
def ExecuteBasePath(self, path, defer=False, **kwargs):
178+
179+
def do_execute(path, **kwargs):
180+
robot = self.robot
181+
with Clone(robot.GetEnv()) as cloned_env:
182+
183+
cloned_robot = cloned_env.Cloned(robot)
184+
cloned_robot.SetActiveDOFs(
185+
[],
186+
affine=(openravepy.DOFAffine.X |
187+
openravepy.DOFAffine.Y |
188+
openravepy.DOFAffine.RotationAxis)
189+
)
190+
191+
cloned_timed_traj = self.retimer.RetimeTrajectory(cloned_robot, path, defer=False, **kwargs)
192+
193+
# Copy the trajectory back to the original environment.
194+
from ..util import CopyTrajectory
195+
timed_traj = CopyTrajectory(cloned_timed_traj, env=robot.GetEnv())
196+
197+
return robot.ExecuteTrajectory(timed_traj, defer=False, **kwargs)
198+
199+
if defer:
200+
from trollius.executor import get_default_executor
201+
from trollius.futures import wrap_future
202+
203+
executor = kwargs.get('executor') or get_default_executor()
204+
return wrap_future(
205+
executor.submit(do_execute,
206+
path, **kwargs
207+
)
208+
)
209+
else:
210+
return do_execute(path, **kwargs)

0 commit comments

Comments
 (0)