Skip to content

Commit c52b328

Browse files
committed
Added a check within snap planner for one-waypoint trajectories.
If a plan is requested that has the same start and goal configuration, SnapPlanner previously returned a two-waypoint trajectory with the same point as the start and goal. This leads to numerical instability and uniqueness problems, because there is no reasonable way to interpolate between the two waypoints, since they occur at the same time and have a delta-time of 0.0. This fix explicitly checks this condition, and only returns a two-waypoint trajectory if start and goal are different.
1 parent dd52a02 commit c52b328

File tree

1 file changed

+21
-17
lines changed

1 file changed

+21
-17
lines changed

src/prpy/planning/snap.py

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
#
77
# Redistribution and use in source and binary forms, with or without
88
# modification, are permitted provided that the following conditions are met:
9-
#
9+
#
1010
# - Redistributions of source code must retain the above copyright notice, this
1111
# list of conditions and the following disclaimer.
1212
# - Redistributions in binary form must reproduce the above copyright notice,
@@ -15,7 +15,7 @@
1515
# - Neither the name of Carnegie Mellon University nor the names of its
1616
# contributors may be used to endorse or promote products derived from this
1717
# software without specific prior written permission.
18-
#
18+
#
1919
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
2020
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2121
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
@@ -32,6 +32,7 @@
3232
from ..util import SetTrajectoryTags
3333
from base import BasePlanner, PlanningError, PlanningMethod, Tags
3434

35+
3536
class SnapPlanner(BasePlanner):
3637
"""Planner that checks the straight-line trajectory to the goal.
3738
@@ -40,15 +41,15 @@ class SnapPlanner(BasePlanner):
4041
due to an environment or self collision, the planner immediately returns
4142
failure by raising a PlanningError. Collision checking is performed using
4243
the standard CheckPathAllConstraints method.
43-
44+
4445
SnapPlanner is intended to be used only as a "short circuit" to speed up
4546
planning between nearby configurations. This planner is most commonly used
4647
as the first item in a Sequence meta-planner to avoid calling a motion
4748
planner when the trivial solution is valid.
4849
"""
4950
def __init__(self):
5051
super(SnapPlanner, self).__init__()
51-
52+
5253
def __str__(self):
5354
return 'SnapPlanner'
5455

@@ -86,7 +87,6 @@ def PlanToEndEffectorPose(self, robot, goal_pose, **kw_args):
8687
# close to the configuration of the arm, so we don't need to do any
8788
# custom IK ranking.
8889
manipulator = robot.GetActiveManipulator()
89-
current_config = robot.GetDOFValues(manipulator.GetArmIndices())
9090
ik_param = openravepy.IkParameterization(goal_pose, ikp.Transform6D)
9191
ik_solution = manipulator.FindIKSolution(
9292
ik_param, ikfo.CheckEnvCollisions,
@@ -101,7 +101,7 @@ def PlanToEndEffectorPose(self, robot, goal_pose, **kw_args):
101101
def _Snap(self, robot, goal, **kw_args):
102102
Closed = openravepy.Interval.Closed
103103

104-
curr = robot.GetActiveDOFValues()
104+
start = robot.GetActiveDOFValues()
105105
active_indices = robot.GetActiveDOFIndices()
106106

107107
# Use the CheckPathAllConstraints helper function to collision check
@@ -110,28 +110,32 @@ def _Snap(self, robot, goal, **kw_args):
110110
params = openravepy.Planner.PlannerParameters()
111111
params.SetRobotActiveJoints(robot)
112112
params.SetGoalConfig(goal)
113-
check = params.CheckPathAllConstraints(curr, goal, [], [], 0., Closed)
113+
check = params.CheckPathAllConstraints(start, goal, [], [], 0., Closed)
114114

115115
# The function returns a bitmask of ConstraintFilterOptions flags,
116116
# indicating which constraints are violated. We'll abort if any
117117
# constraints are violated.
118118
if check != 0:
119119
raise PlanningError('Straight line trajectory is not valid.')
120120

121-
# Create a two-point trajectory that starts at our current
122-
# configuration and takes us to the goal.
123-
traj = openravepy.RaveCreateTrajectory(self.env, '')
121+
# Create a trajectory that starts at our current configuration.
124122
cspec = robot.GetActiveConfigurationSpecification()
125-
active_indices = robot.GetActiveDOFIndices()
123+
traj = openravepy.RaveCreateTrajectory(self.env, '')
124+
traj.Init(cspec)
126125

127-
waypoints = numpy.zeros((2, cspec.GetDOF()))
128-
cspec.InsertJointValues(waypoints[0, :], curr, robot,
129-
active_indices, False)
130-
cspec.InsertJointValues(waypoints[1, :], goal, robot,
126+
start_waypoint = numpy.zeros(cspec.GetDOF())
127+
cspec.InsertJointValues(start_waypoint, start, robot,
131128
active_indices, False)
129+
traj.Insert(0, start_waypoint.ravel())
132130

133-
traj.Init(cspec)
134-
traj.Insert(0, waypoints.ravel())
131+
# Make the trajectory end at the goal configuration, as long as it
132+
# was not identical to the start configuration.
133+
if not numpy.allclose(start, goal):
134+
goal_waypoint = numpy.zeros(cspec.GetDOF())
135+
cspec.InsertJointValues(goal_waypoint, goal, robot,
136+
active_indices, False)
137+
traj.Insert(1, goal_waypoint.ravel())
135138

139+
# Tag the return trajectory as smooth (in joint space) and return it.
136140
SetTrajectoryTags(traj, {Tags.SMOOTH: True}, append=True)
137141
return traj

0 commit comments

Comments
 (0)