SkillAgentSearch skills...

Prpy

Python utilities used by the Personal Robotics Laboratory.

Install / Use

/learn @personalrobotics/Prpy
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

PrPy

Build Status

PrPy is a Python library used by the Personal Robotics Laboratory at Carnegie Mellon University. This library includes robot-agnostic utilities that make it easier to use OpenRAVE in Python scripts. This includes a high-level planning pipeline, helper functions, and visualization tools.

Planning Pipeline

There are a large array of motion planners that have complementary strengths and weaknesses. PrPy provides a planning pipeline in the prpy.planning namespace that makes it easy plan with multiple planners in parallel on a single problem. Additionally, the planning pipeline takes advantage of the dynamic nature of Python to mix-and-match planners with heterogeneous capabilities.

Every planner used in the PrPy planning pipeline extends the prpy.planning.base.Planner class. Typically, a planner will extend one of two subclasses:

  1. prpy.planning.base.BasePlanner: implements or wraps a motion planner
  2. prpy.planning.base.MetaPlanner: combines the output of multiple motion planners, each of which is a BasePlanner or another MetaPlanner

Each planner has one or more planning methods, annotated with either the @LockedPlanningMethod or @ClonedPlanningMethod decorator, that look like ordinary functions. Using these decorators makes other PrPy components aware that these methods exist and follow a particular specification that allows them to be composed with other PrPy objects automatically. For example, MetaPlanners will report that they can perform planning methods that their child motion planners have enumerated via @PlanningMethod decorators.

@PlanningMethod decorators also make sure that calls to planning code are executed in a thread-safe manner. In the case of @LockedPlanningMethod, this is enforced by locking the calling environment until the planning method has completed. In the case of @ClonedPlanningMethod, this is enforced by cloning the calling environment, and calling the wrapped method with references to the cloned environment. The result of the method is then copied back to the calling environment. @ClonedPlanningMethods can be used to run multiple planners in parallel and to parallelize planning and execution.

In general, locked planning methods are used for calls that will terminate extremely quickly, while cloned planning methods are used for calls that might take a significant amount of time.

For example, the following code will use OMPL to plan robot's active DOFs from their current values to to the goal_config configuration:

planner = OMPLPlanner('RRTConnect')
output_path = planner.PlanToConfiguration(robot, goal_config)

As this is a @ClonedPlanningMethod, robot.GetEnv() is cloned into the the planner.env planning environment. Planning occurs within this cloned environment. Finally, the output path is cloned back into robot.GetEnv() and is returned by the planner.

See the following sub-sections for more information about the built-in planners provided with PrPy, information about writing your own planner, and several more complex usage examples.

Built-In Planners

PrPy provides wrappers for several existing planning libraries:

Additionally, PrPy provides several simple planners of its own:

  • MKPlanner: Jacobian pseudo-inverse controller for executing straight-line workspace trajectories
  • SnapPlanner: attempts to execute a straight-line joint-space trajectory to the goal
  • GreedyIKPlanner: follows a workspace path by greedily picking IK solutions
  • VectorFieldPlanner: follows any custom cspace vector field until a custom termination

Finally, PrPy provides several meta-planners for combining the above planners:

  • Sequence: sequentially queries a list of planners and returns the result of the first planner in the list that succeeds.
  • Ranked: queries a list of planners in parallel and returns the solution first planner in the list that returns success
  • IKPlanner: plan to an end-effector pose by sequentially planning to a list of ranked IK solutions
  • NamedPlanner: plan to a named configuration associated with the robot

See the Python docstrings in the above classes for more information.

Common Planning Methods

There is no formal list of @*PlanningMethods or their arguments. However, we have found these methods to be useful:

  • PlanToConfiguration(robot, goal_config): plan the robot's active DOFs from the robot's current configuration to the goal_config configuration.
  • PlanToConfigurations(robot, goal_configs): plan the robot's active DOFs from the robot's current configuration to any of the elements in the goal_configs list.
  • PlanToEndEffectorPose(robot, goal_pose): plan the robot's active manipulator's end-effector to goal_pose.
  • PlanToEndEffectorOffset(robot, direction, min_distance, max_distance): plan the robot's active manipulator in a straight line in the direction specified by the direction unit vector for [ min_distance, max_distance ] meters.
  • PlanToTSR(robot, tsrchains): plan with the start, goal, and/or constraints specified by a list of TSR chains.
  • PlanToBasePose(robot, goal_pose): plan with the robot's affine DOFs in the plane to a desired base pose.

Most planners that implement these methods accept a timelimit parameter, in seconds, for which to plan before raising a PlanningError. Additionally, many of these methods accept planner-specific keyword arguments.

Writing a Custom Planner

Implementing a custom planner requires extending the BasePlanner class and decorating one or more methods with the @LockedPlanningMethod or @ClonedPlanningMethod decorator.

Extending the BasePlanner class allows PrPy to identify your planner as a base planner class, as opposed to a meta-planner. The @PlanningMethod decorators handle environment cloning or locking and allows meta-planners to query the list of planning methods that the planner supports (e.g. to generate docstrings).

Each instance of a BasePlanner-derived class constructs a planning environment self.env. This environment is uniquely associated with each instance of the planner and is what will be used in @ClonedPlanningMethod calls. Since this environment is persistent and unique, it can also be used as a place to cache data or pre-load plugins for planners that have heavyweight initialization steps. However, because of this, each planning instance can only execute one @ClonedPlanningMethod at a time. It can still execute arbitrary @LockedPlanningMethod calls, as long as they are referring to robots in different environments.

Please obey the following guidelines:

  • Assume that the planning environment is locked during the entire call.
  • Subclass constructors must call BasePlanner.__init__.
  • Each @PlanningMethod must accept the first argument robot, which is a robot in the environment it should be using to perform planning.
  • Each @PlanningMethod must accept **kwargs to ignore arguments that are not supported by the planner.
  • Each @PlanningMethod must return a Trajectory which was created in the same environment as the robot it was passed (e.g. robot.GetEnv()).
  • When possible, use one of the defacto-standard @*PlanningMethod names listed below.
  • Raise a PlanningError to indicate an expected, but fatal, error (e.g. timeout with no collision-free path).
  • When applicable, raise a context-specific subclass of PlanningError to indicate the nature of the error (e.g. StartCollisionPlanningError)
  • Raise a standard Python exception, e.g. ValueError, to indicate an unexpected error has occurred (e.g. argument out of range).
  • Raise a UnsupportedPlanningError to indicate that the planning operation is fundamentally not supported (e.g. constraint type is not implemented).

Examples

Trajectory optimizers, like CHOMP, typically produce higher quality paths than randomized planners. However, these algorithms are not probabilistically complete and can get stuck in local minima. You can mitigate this by using the Sequence planner to first call CHOMP, then fall back on RRT-Connect:

planner = Sequence(CHOMPPlanner(), OMPLPlanner('RRTConnect'))
path = planner.PlanToConfiguration(robot, goal)

Unfortunately, this means that RRT-Connect does not start planning until CHOMP has already failed to find a solution. Instead of using Sequence, we can use the Ranked meta-planner to plan with both planners in parallel. Just as before, the meta-planner will immediately return CHOMP's solution if it returns success. However, RRT-Connect will have a head-start if CHOMP fails:

planner = Ranked(CHOMPPlanner(), OMPLPlanner('RRTConnect'))
path = planner.PlanToConfiguration(robot, goal)`

In other cases, a meta-planner can be used to combine the disparate capabilities of multiple planenrs. For example,

Related Skills

View on GitHub
GitHub Stars65
CategoryDevelopment
Updated2mo ago
Forks20

Languages

Python

Security Score

95/100

Audited on Jan 22, 2026

No findings