Skip to content

Commit a620442

Browse files
committed
(ompl interface) add new state validity checker for ompl constrained planning
1 parent f2fbaee commit a620442

4 files changed

Lines changed: 500 additions & 4 deletions

File tree

moveit_planners/ompl/ompl_interface/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,4 +54,8 @@ if(CATKIN_ENABLE_TESTING)
5454
catkin_add_gtest(test_constrained_planning_state_space test/test_constrained_planning_state_space.cpp)
5555
target_link_libraries(test_constrained_planning_state_space ${MOVEIT_LIB_NAME} ${OMPL_LIBRARIES} ${catkin_LIBRARIES})
5656
set_target_properties(test_constrained_planning_state_space PROPERTIES LINK_FLAGS "${OpenMP_CXX_FLAGS}")
57+
58+
catkin_add_gtest(test_constrained_state_validity_checker test/test_constrained_state_validity_checker.cpp)
59+
target_link_libraries(test_constrained_state_validity_checker ${MOVEIT_LIB_NAME} ${OMPL_LIBRARIES} ${catkin_LIBRARIES})
60+
set_target_properties(test_constrained_state_validity_checker PROPERTIES LINK_FLAGS "${OpenMP_CXX_FLAGS}")
5761
endif()

moveit_planners/ompl/ompl_interface/include/moveit/ompl_interface/detail/state_validity_checker.h

Lines changed: 59 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
* POSSIBILITY OF SUCH DAMAGE.
3333
*********************************************************************/
3434

35-
/* Author: Ioan Sucan */
35+
/* Authors: Ioan Sucan, Jeroen De Maeyer */
3636

3737
#pragma once
3838

@@ -61,8 +61,8 @@ class StateValidityChecker : public ompl::base::StateValidityChecker
6161
return isValid(state, dist, verbose_);
6262
}
6363

64-
bool isValid(const ompl::base::State* state, bool verbose) const;
65-
bool isValid(const ompl::base::State* state, double& dist, bool verbose) const;
64+
virtual bool isValid(const ompl::base::State* state, bool verbose) const;
65+
virtual bool isValid(const ompl::base::State* state, double& dist, bool verbose) const;
6666

6767
virtual double cost(const ompl::base::State* state) const;
6868
double clearance(const ompl::base::State* state) const override;
@@ -81,4 +81,60 @@ class StateValidityChecker : public ompl::base::StateValidityChecker
8181
collision_detection::CollisionRequest collision_request_with_cost_;
8282
bool verbose_;
8383
};
84+
85+
/** \brief A StateValidityChecker that can handle states of type `ompl::base::ConstraintStateSpace::StateType`.
86+
*
87+
* We cannot not just cast the states and pass them to the isValid version of the parent class, because inside the
88+
* state-validity checker, the line:
89+
*
90+
* planning_context_->getOMPLStateSpace()->copyToRobotState(*robot_state, state);
91+
*
92+
* requires the state type to be of the constrained state space, while:
93+
*
94+
* state->as<ModelBasedStateSpace::StateType>()->isValidityKnown()
95+
*
96+
* requires accessing the underlying state by calling `getState()` on the constrained state space state.
97+
* Therefore this class implements specific versions of the isValid methods.
98+
*
99+
* We still check the path constraints, because not all states sampled by the constrained state space
100+
* satisfy the constraints unfortunately. This is a complicated issue. For more details see:
101+
* https://github.com/ros-planning/moveit/issues/2092#issuecomment-669911722.
102+
**/
103+
class ConstrainedPlanningStateValidityChecker : public StateValidityChecker
104+
{
105+
public:
106+
using StateValidityChecker::isValid;
107+
108+
public:
109+
ConstrainedPlanningStateValidityChecker(const ModelBasedPlanningContext* planning_context)
110+
: StateValidityChecker(planning_context)
111+
{
112+
}
113+
114+
/** \brief Check validity for states of type ompl::base::ConstrainedStateSpace
115+
*
116+
* This state type is special in that it "wraps" around a normal state,
117+
* which can be accessed by the getState() method. In this class we assume that this state,
118+
* is of type `ompl_interface::ConstrainedPlanningStateSpace`, which inherits from
119+
* `ompl_interface::ModelBasedStateSpace`.
120+
*
121+
* (For the actual implementation of this, look at the ompl::base::WrapperStateSpace.)
122+
*
123+
* Code sample that can be used to check all the assumptions:
124+
*
125+
* #include <moveit/ompl_interface/parameterization/joint_space/constrained_planning_state_space.h>
126+
* #include <ompl/base/ConstrainedSpaceInformation.h>
127+
*
128+
* // the code below should be pasted at the top of the isValid method
129+
* auto css = dynamic_cast<const ompl::base::ConstrainedStateSpace::StateType*>(wrapped_state);
130+
* assert(css != nullptr);
131+
* auto cpss = dynamic_cast<const ConstrainedPlanningStateSpace*>(planning_context_->getOMPLStateSpace().get());
132+
* assert(cpss != nullptr);
133+
* auto cssi = dynamic_cast<const ompl::base::ConstrainedSpaceInformation*>(si_);
134+
* assert(cssi != nullptr);
135+
*
136+
**/
137+
bool isValid(const ompl::base::State* wrapped_state, bool verbose) const override;
138+
bool isValid(const ompl::base::State* wrapped_state, double& dist, bool verbose) const override;
139+
};
84140
} // namespace ompl_interface

moveit_planners/ompl/ompl_interface/src/detail/state_validity_checker.cpp

Lines changed: 111 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,15 @@
3232
* POSSIBILITY OF SUCH DAMAGE.
3333
*********************************************************************/
3434

35-
/* Author: Ioan Sucan */
35+
/* Authors: Ioan Sucan, Jeroen De Maeyer */
3636

3737
#include <moveit/ompl_interface/detail/state_validity_checker.h>
3838
#include <moveit/ompl_interface/model_based_planning_context.h>
3939
#include <moveit/profiler/profiler.h>
4040
#include <ros/ros.h>
4141

42+
#include <ompl/base/spaces/constraint/ConstrainedStateSpace.h>
43+
4244
namespace ompl_interface
4345
{
4446
constexpr char LOGNAME[] = "state_validity_checker";
@@ -194,4 +196,112 @@ double ompl_interface::StateValidityChecker::clearance(const ompl::base::State*
194196
collision_detection::CollisionResult res;
195197
planning_context_->getPlanningScene()->checkCollision(collision_request_with_distance_, res, *robot_state);
196198
return res.collision ? 0.0 : (res.distance < 0.0 ? std::numeric_limits<double>::infinity() : res.distance);
199+
}
200+
201+
/*******************************************
202+
* Constrained Planning StateValidityChecker
203+
* *****************************************/
204+
205+
bool ompl_interface::ConstrainedPlanningStateValidityChecker::isValid(const ompl::base::State* wrapped_state,
206+
bool verbose) const
207+
{
208+
// Unwrap the state from a ConstrainedStateSpace::StateType
209+
auto state = wrapped_state->as<ompl::base::ConstrainedStateSpace::StateType>()->getState();
210+
211+
// Use cached validity if it is available
212+
if (state->as<ModelBasedStateSpace::StateType>()->isValidityKnown())
213+
return state->as<ModelBasedStateSpace::StateType>()->isMarkedValid();
214+
215+
// do not use the unwrapped state here, as satisfiesBounds expects a state of type ConstrainedStateSpace::StateType
216+
if (!si_->satisfiesBounds(wrapped_state))
217+
{
218+
if (verbose)
219+
ROS_INFO_NAMED(LOGNAME, "State outside bounds");
220+
const_cast<ob::State*>(state)->as<ModelBasedStateSpace::StateType>()->markInvalid();
221+
return false;
222+
}
223+
224+
moveit::core::RobotState* robot_state = tss_.getStateStorage();
225+
// do not use the unwrapped state here, as copyToRobotState expects a state of type ConstrainedStateSpace::StateType
226+
planning_context_->getOMPLStateSpace()->copyToRobotState(*robot_state, wrapped_state);
227+
228+
// check path constraints
229+
const kinematic_constraints::KinematicConstraintSetPtr& kset = planning_context_->getPathConstraints();
230+
if (kset && !kset->decide(*robot_state, verbose).satisfied)
231+
{
232+
const_cast<ob::State*>(state)->as<ModelBasedStateSpace::StateType>()->markInvalid();
233+
return false;
234+
}
235+
236+
// check feasibility
237+
if (!planning_context_->getPlanningScene()->isStateFeasible(*robot_state, verbose))
238+
{
239+
const_cast<ob::State*>(state)->as<ModelBasedStateSpace::StateType>()->markInvalid();
240+
return false;
241+
}
242+
243+
// check collision avoidance
244+
collision_detection::CollisionResult res;
245+
planning_context_->getPlanningScene()->checkCollision(
246+
verbose ? collision_request_simple_verbose_ : collision_request_simple_, res, *robot_state);
247+
if (!res.collision)
248+
{
249+
const_cast<ob::State*>(state)->as<ModelBasedStateSpace::StateType>()->markValid();
250+
}
251+
else
252+
{
253+
const_cast<ob::State*>(state)->as<ModelBasedStateSpace::StateType>()->markInvalid();
254+
}
255+
return !res.collision;
256+
}
257+
258+
bool ompl_interface::ConstrainedPlanningStateValidityChecker::isValid(const ompl::base::State* wrapped_state,
259+
double& dist, bool verbose) const
260+
{
261+
// Unwrap the state from a ConstrainedStateSpace::StateType
262+
auto state = wrapped_state->as<ompl::base::ConstrainedStateSpace::StateType>()->getState();
263+
264+
// Use cached validity and distance if they are available
265+
if (state->as<ModelBasedStateSpace::StateType>()->isValidityKnown() &&
266+
state->as<ModelBasedStateSpace::StateType>()->isGoalDistanceKnown())
267+
{
268+
dist = state->as<ModelBasedStateSpace::StateType>()->distance;
269+
return state->as<ModelBasedStateSpace::StateType>()->isMarkedValid();
270+
}
271+
272+
// do not use the unwrapped state here, as satisfiesBounds expects a state of type ConstrainedStateSpace::StateType
273+
if (!si_->satisfiesBounds(wrapped_state))
274+
{
275+
if (verbose)
276+
ROS_INFO_NAMED(LOGNAME, "State outside bounds");
277+
const_cast<ob::State*>(state)->as<ModelBasedStateSpace::StateType>()->markInvalid(0.0);
278+
return false;
279+
}
280+
281+
moveit::core::RobotState* robot_state = tss_.getStateStorage();
282+
283+
// do not use the unwrapped state here, as copyToRobotState expects a state of type ConstrainedStateSpace::StateType
284+
planning_context_->getOMPLStateSpace()->copyToRobotState(*robot_state, wrapped_state);
285+
286+
// check path constraints
287+
const kinematic_constraints::KinematicConstraintSetPtr& kset = planning_context_->getPathConstraints();
288+
if (kset && !kset->decide(*robot_state, verbose).satisfied)
289+
{
290+
const_cast<ob::State*>(state)->as<ModelBasedStateSpace::StateType>()->markInvalid();
291+
return false;
292+
}
293+
294+
// check feasibility
295+
if (!planning_context_->getPlanningScene()->isStateFeasible(*robot_state, verbose))
296+
{
297+
dist = 0.0;
298+
return false;
299+
}
300+
301+
// check collision avoidance
302+
collision_detection::CollisionResult res;
303+
planning_context_->getPlanningScene()->checkCollision(
304+
verbose ? collision_request_with_distance_verbose_ : collision_request_with_distance_, res, *robot_state);
305+
dist = res.distance;
306+
return !res.collision;
197307
}

0 commit comments

Comments
 (0)