Skip to content

Commit 5d42914

Browse files
committed
Merge pull request #228 from DavidB-CMU/master
Added method for collision checking trajectories.
2 parents 11b6ec8 + aca72e7 commit 5d42914

File tree

3 files changed

+866
-98
lines changed

3 files changed

+866
-98
lines changed

src/prpy/planning/snap.py

Lines changed: 83 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -29,23 +29,25 @@
2929
# POSSIBILITY OF SUCH DAMAGE.
3030
import numpy
3131
import openravepy
32-
from ..util import SetTrajectoryTags
33-
from base import BasePlanner, PlanningError, PlanningMethod, Tags
32+
from prpy.util import SetTrajectoryTags
33+
from prpy.planning.base import BasePlanner
34+
from prpy.planning.base import PlanningError
35+
from prpy.planning.base import PlanningMethod
36+
from prpy.planning.base import Tags
3437

3538

3639
class SnapPlanner(BasePlanner):
3740
"""Planner that checks the straight-line trajectory to the goal.
3841
3942
SnapPlanner is a utility planner class that collision checks the
40-
straight-line trajectory to the goal. If that trajectory is invalid, i.e..
41-
due to an environment or self collision, the planner immediately returns
42-
failure by raising a PlanningError. Collision checking is performed using
43-
the standard CheckPathAllConstraints method.
44-
45-
SnapPlanner is intended to be used only as a "short circuit" to speed up
46-
planning between nearby configurations. This planner is most commonly used
47-
as the first item in a Sequence meta-planner to avoid calling a motion
48-
planner when the trivial solution is valid.
43+
straight-line trajectory to the goal. If that trajectory is invalid,
44+
e.g. due to an environment or self collision, the planner
45+
immediately returns failure by raising a PlanningError.
46+
47+
SnapPlanner is intended to be used only as a "short circuit" to
48+
speed-up planning between nearby configurations. This planner is
49+
most commonly used as the first item in a Sequence meta-planner to
50+
avoid calling a motion planner when the trivial solution is valid.
4951
"""
5052
def __init__(self):
5153
super(SnapPlanner, self).__init__()
@@ -56,34 +58,35 @@ def __str__(self):
5658
@PlanningMethod
5759
def PlanToConfiguration(self, robot, goal, **kw_args):
5860
"""
59-
Attempt to plan a straight line trajectory from the robot's current
60-
configuration to the goal configuration. This will fail if the
61-
straight-line path is not collision free.
61+
Attempt to plan a straight line trajectory from the robot's
62+
current configuration to the goal configuration. This will
63+
fail if the straight-line path is not collision free.
6264
6365
@param robot
6466
@param goal desired configuration
6567
@return traj
6668
"""
69+
6770
return self._Snap(robot, goal, **kw_args)
6871

6972
@PlanningMethod
7073
def PlanToEndEffectorPose(self, robot, goal_pose, **kw_args):
7174
"""
72-
Attempt to plan a straight line trajectory from the robot's current
73-
configuration to a desired end-effector pose. This happens by finding
74-
the closest IK solution to the robot's current configuration and
75-
attempts to snap there (using PlanToConfiguration) if possible. In the
76-
case of a redundant manipulator, no attempt is made to check other IK
77-
solutions.
75+
Attempt to plan a straight line trajectory from the robot's
76+
current configuration to a desired end-effector pose. This
77+
happens by finding the closest IK solution to the robot's
78+
current configuration and attempts to snap there
79+
(using PlanToConfiguration) if possible.
80+
In the case of a redundant manipulator, no attempt is
81+
made to check other IK solutions.
7882
7983
@param robot
8084
@param goal_pose desired end-effector pose
8185
@return traj
8286
"""
83-
84-
from .exceptions import CollisionPlanningError,SelfCollisionPlanningError
85-
from openravepy import CollisionReport
86-
87+
from prpy.planning.exceptions import CollisionPlanningError
88+
from prpy.planning.exceptions import SelfCollisionPlanningError
89+
8790
ikp = openravepy.IkParameterizationType
8891
ikfo = openravepy.IkFilterOptions
8992

@@ -99,17 +102,16 @@ def PlanToEndEffectorPose(self, robot, goal_pose, **kw_args):
99102

100103
if ik_solution is None:
101104
# FindIKSolutions is slower than FindIKSolution,
102-
# so call this only to identify and raise error when there is no solution
105+
# so call this only to identify and raise error when
106+
# there is no solution
103107
ik_solutions = manipulator.FindIKSolutions(
104-
ik_param,
105-
ikfo.IgnoreSelfCollisions,
106-
ikreturn=False,
107-
releasegil=True
108-
)
109-
108+
ik_param,
109+
ikfo.IgnoreSelfCollisions,
110+
ikreturn=False,
111+
releasegil=True)
110112
for q in ik_solutions:
111113
robot.SetActiveDOFValues(q)
112-
report = CollisionReport()
114+
report = openravepy.CollisionReport()
113115
if self.env.CheckCollision(robot, report=report):
114116
raise CollisionPlanningError.FromReport(report)
115117
elif robot.CheckSelfCollision(report=report):
@@ -120,81 +122,70 @@ def PlanToEndEffectorPose(self, robot, goal_pose, **kw_args):
120122
return self._Snap(robot, ik_solution, **kw_args)
121123

122124
def _Snap(self, robot, goal, **kw_args):
123-
from .exceptions import CollisionPlanningError,SelfCollisionPlanningError,JointLimitError
124-
from openravepy import CollisionReport
125-
126-
Closed = openravepy.Interval.Closed
127-
128-
start = robot.GetActiveDOFValues()
129-
active_indices = robot.GetActiveDOFIndices()
130-
131-
# Use the CheckPathAllConstraints helper function to collision check
132-
# the straight-line trajectory. We pass dummy values for dq0, dq1,
133-
# and timeelapsed since this is a purely geometric check.
134-
params = openravepy.Planner.PlannerParameters()
135-
params.SetRobotActiveJoints(robot)
136-
params.SetGoalConfig(goal)
137-
check = params.CheckPathAllConstraints(start, goal, [], [], 0., Closed,
138-
options = 15, returnconfigurations = True)
139-
140-
# If valid, above function returns (0,None, None, 0)
141-
# if not, it returns (1, invalid_config ,[], time_when_invalid),
142-
# in which case we identify and raise appropriate error.
143-
if check[0] != 0:
144-
q = check[1]
145-
146-
# Check for joint limit violation
147-
q_limit_min, q_limit_max = robot.GetActiveDOFLimits()
148-
149-
lower_position_violations = (q < q_limit_min)
150-
if lower_position_violations.any():
151-
index = lower_position_violations.nonzero()[0][0]
152-
raise JointLimitError(robot,
153-
dof_index=active_indices[index],
154-
dof_value=q[index],
155-
dof_limit=q_limit_min[index],
156-
description='position')
157-
158-
upper_position_violations = (q> q_limit_max)
159-
if upper_position_violations.any():
160-
index = upper_position_violations.nonzero()[0][0]
161-
raise JointLimitError(robot,
162-
dof_index=active_indices[index],
163-
dof_value=q[index],
164-
dof_limit=q_limit_max[index],
165-
description='position')
166-
167-
# Check for collision
168-
robot.SetActiveDOFValues(q)
169-
report = CollisionReport()
170-
if self.env.CheckCollision(robot, report=report):
171-
raise CollisionPlanningError.FromReport(report)
172-
elif robot.CheckSelfCollision(report=report):
173-
raise SelfCollisionPlanningError.FromReport(report)
174-
175-
raise PlanningError('Straight line trajectory is not valid.' )
176-
177-
# Create a two-point trajectory that starts at our current
178-
# configuration and takes us to the goal.
125+
from prpy.util import CheckJointLimits
126+
from prpy.util import GetLinearCollisionCheckPts
127+
#from prpy.util import SampleTimeGenerator
128+
from prpy.util import VanDerCorputSampleGenerator
129+
from prpy.planning.exceptions import CollisionPlanningError
130+
from prpy.planning.exceptions import SelfCollisionPlanningError
131+
132+
# Create a two-point trajectory between the
133+
# current configuration and the goal.
134+
# (a straight line in joint space)
179135
traj = openravepy.RaveCreateTrajectory(self.env, '')
180136
cspec = robot.GetActiveConfigurationSpecification('linear')
181137
active_indices = robot.GetActiveDOFIndices()
182138

139+
# Check the start position is within joint limits,
140+
# this can throw a JointLimitError
141+
start = robot.GetActiveDOFValues()
142+
CheckJointLimits(robot, start)
143+
144+
# Add the start waypoint
183145
start_waypoint = numpy.zeros(cspec.GetDOF())
184146
cspec.InsertJointValues(start_waypoint, start, robot,
185147
active_indices, False)
186-
187148
traj.Init(cspec)
188149
traj.Insert(0, start_waypoint.ravel())
189150

190-
# Make the trajectory end at the goal configuration, as long as it
191-
# was not identical to the start configuration.
151+
# Make the trajectory end at the goal configuration, as
152+
# long as it is not in collision and is not identical to
153+
# the start configuration.
154+
CheckJointLimits(robot, goal)
192155
if not numpy.allclose(start, goal):
193156
goal_waypoint = numpy.zeros(cspec.GetDOF())
194157
cspec.InsertJointValues(goal_waypoint, goal, robot,
195158
active_indices, False)
196159
traj.Insert(1, goal_waypoint.ravel())
197160

198-
# Tag the return trajectory as smooth (in joint space) and return it.
161+
# Get joint configurations to check
162+
# Note: this returns a python generator, and if the
163+
# trajectory only has one waypoint then only the
164+
# start configuration will be collisioned checked.
165+
#
166+
# Sampling function:
167+
# 'linear'
168+
#linear = SampleTimeGenerator
169+
# 'Van der Corput'
170+
vdc = VanDerCorputSampleGenerator
171+
checks = GetLinearCollisionCheckPts(robot, \
172+
traj, \
173+
norm_order=2, \
174+
sampling_func=vdc)
175+
176+
# Run constraint checks at DOF resolution:
177+
for t, q in checks:
178+
# Set the joint positions
179+
# Note: the planner is using a cloned 'robot' object
180+
robot.SetActiveDOFValues(q)
181+
182+
# Check for collisions
183+
report = openravepy.CollisionReport()
184+
if self.env.CheckCollision(robot, report=report):
185+
raise CollisionPlanningError.FromReport(report)
186+
elif robot.CheckSelfCollision(report=report):
187+
raise SelfCollisionPlanningError.FromReport(report)
188+
189+
# Tag the return trajectory as smooth (in joint space).
199190
SetTrajectoryTags(traj, {Tags.SMOOTH: True}, append=True)
200191
return traj

0 commit comments

Comments
 (0)