Skip to content

Commit e9eab62

Browse files
authored
Enable collisions visualizations (#708)
1 parent 336ad44 commit e9eab62

8 files changed

Lines changed: 113 additions & 21 deletions

File tree

core/include/moveit/task_constructor/storage.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -335,7 +335,7 @@ class SolutionBase
335335
// comment for this solution, e.g. explanation of failure
336336
std::string comment_;
337337
// markers for this solution, e.g. target frame or collision indicators
338-
std::deque<visualization_msgs::Marker> markers_;
338+
std::vector<visualization_msgs::Marker> markers_;
339339

340340
// begin and end InterfaceState of this solution/trajectory
341341
const InterfaceState* start_ = nullptr;

core/include/moveit/task_constructor/utils.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@
4545
#include <Eigen/Geometry>
4646

4747
#include <moveit/macros/class_forward.h>
48+
#include <moveit/robot_trajectory/robot_trajectory.h>
49+
#include <moveit/collision_detection/collision_common.h>
50+
#include <moveit/task_constructor/solvers/planner_interface.h>
4851

4952
namespace planning_scene {
5053
MOVEIT_CLASS_FORWARD(PlanningScene);
@@ -143,6 +146,19 @@ class Flags
143146
bool getRobotTipForFrame(const Property& tip_pose, const planning_scene::PlanningScene& scene,
144147
const moveit::core::JointModelGroup* jmg, std::string& error_msg,
145148
const moveit::core::LinkModel*& robot_link, Eigen::Isometry3d& tip_in_global_frame);
149+
150+
/** Add sphere markers to visualize given collisions */
151+
void addCollisionMarkers(std::vector<visualization_msgs::Marker>& markers, const std::string& frame_id,
152+
const collision_detection::CollisionResult::ContactMap& contacts, double radius = 0.035);
153+
154+
/** Add sphere markers to visualize collisions within the trajectory */
155+
void addCollisionMarkers(std::vector<visualization_msgs::Marker>& markers,
156+
const robot_trajectory::RobotTrajectory& trajectory,
157+
const planning_scene::PlanningSceneConstPtr& planning_scene);
158+
159+
/** Returns true if the result provides hints that planning failed due to collisions */
160+
bool hints_at_collisions(const solvers::PlannerInterface::Result& result);
161+
146162
} // namespace utils
147163
} // namespace task_constructor
148164
} // namespace moveit

core/src/stages/compute_ik.cpp

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ void ComputeIK::setTargetPose(const Eigen::Isometry3d& pose, const std::string&
8989
struct IKSolution
9090
{
9191
std::vector<double> joint_positions;
92-
collision_detection::Contact contact;
92+
collision_detection::CollisionResult::ContactMap contacts;
9393
bool collision_free;
9494
bool satisfies_constraints;
9595
};
@@ -141,7 +141,7 @@ bool isTargetPoseCollidingInEEF(const planning_scene::PlanningSceneConstPtr& sce
141141
}
142142

143143
std::string listCollisionPairs(const collision_detection::CollisionResult::ContactMap& contacts,
144-
const std::string& separator) {
144+
const std::string& separator = ", ") {
145145
std::string result;
146146
for (const auto& contact : contacts) {
147147
if (!result.empty())
@@ -345,8 +345,8 @@ void ComputeIK::compute() {
345345
generateCollisionMarkers(sandbox_state, appender, links_to_visualize);
346346
std::copy(eef_markers.begin(), eef_markers.end(), std::back_inserter(solution.markers()));
347347
solution.markAsFailure();
348-
// TODO: visualize collisions
349-
solution.setComment(s.comment() + " eef in collision: " + listCollisionPairs(collisions.contacts, ", "));
348+
solution.setComment(s.comment() + " eef in collision: " + listCollisionPairs(collisions.contacts));
349+
utils::addCollisionMarkers(solution.markers(), scene->getPlanningFrame(), collisions.contacts);
350350
auto colliding_scene{ scene->diff() };
351351
colliding_scene->setCurrentState(sandbox_state);
352352
spawn(InterfaceState(colliding_scene), std::move(solution));
@@ -395,9 +395,7 @@ void ComputeIK::compute() {
395395
req.group_name = jmg->getName();
396396
scene->checkCollision(req, res, *state);
397397
solution.collision_free = ignore_collisions || !res.collision;
398-
if (!res.contacts.empty()) {
399-
solution.contact = res.contacts.begin()->second.front();
400-
}
398+
solution.contacts = std::move(res.contacts);
401399

402400
return solution.satisfies_constraints && solution.collision_free;
403401
};
@@ -433,10 +431,8 @@ void ComputeIK::compute() {
433431
// compute cost as distance to compare_pose
434432
solution.setCost(s.cost() + jmg->distance(ik_solutions[i].joint_positions.data(), compare_pose.data()));
435433
else if (!ik_solutions[i].collision_free) { // solution was in collision
436-
std::stringstream ss;
437-
ss << "Collision between '" << ik_solutions[i].contact.body_name_1 << "' and '"
438-
<< ik_solutions[i].contact.body_name_2 << "'";
439-
solution.markAsFailure(ss.str());
434+
solution.markAsFailure("Collision between " + listCollisionPairs(ik_solutions[i].contacts));
435+
utils::addCollisionMarkers(solution.markers(), scene->getPlanningFrame(), ik_solutions[i].contacts);
440436
} else if (!ik_solutions[i].satisfies_constraints) { // solution was violating constraints
441437
solution.markAsFailure("Constraints violated");
442438
}

core/src/stages/connect.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@ void Connect::compute(const InterfaceState& from, const InterfaceState& to) {
150150
intermediate_scenes.push_back(start);
151151

152152
bool success = false;
153+
bool has_potential_collisions = false;
153154
std::string comment = "No planners specified";
154155
std::vector<double> positions;
155156
for (const GroupPlannerVector::value_type& pair : planner_) {
@@ -169,6 +170,7 @@ void Connect::compute(const InterfaceState& from, const InterfaceState& to) {
169170

170171
if (!success) {
171172
comment = result.message;
173+
has_potential_collisions = trajectory && utils::hints_at_collisions(result);
172174
break;
173175
}
174176

@@ -187,8 +189,15 @@ void Connect::compute(const InterfaceState& from, const InterfaceState& to) {
187189
solution = merge(sub_trajectories, intermediate_scenes, from.scene()->getCurrentState());
188190
if (!solution) // success == false or merging failed: store sequentially
189191
solution = makeSequential(sub_trajectories, intermediate_scenes, from, to);
190-
if (!success) // error during sequential planning
192+
if (!success) { // error already during sequential planning
191193
solution->markAsFailure(comment);
194+
if (has_potential_collisions) {
195+
// add collision markers for last (failed) trajectory segment
196+
auto sequence = std::dynamic_pointer_cast<SolutionSequence>(solution);
197+
auto trajectory = dynamic_cast<const SubTrajectory*>(sequence->solutions().back())->trajectory();
198+
utils::addCollisionMarkers(solution->markers(), *trajectory, start);
199+
}
200+
}
192201
connect(from, to, solution);
193202
}
194203

core/src/stages/modify_planning_scene.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@ std::pair<InterfaceState, SubTrajectory> ModifyPlanningScene::apply(const Interf
163163
if (res.collision) {
164164
const auto contact = res.contacts.begin()->second.front();
165165
traj.markAsFailure(contact.body_name_1 + " colliding with " + contact.body_name_2);
166+
utils::addCollisionMarkers(traj.markers(), scene->getPlanningFrame(), res.contacts);
166167
}
167168
} catch (const std::exception& e) {
168169
traj.markAsFailure(e.what());

core/src/stages/move_relative.cpp

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ static bool getJointStateFromOffset(const boost::any& direction, const Interface
105105
}
106106

107107
// Create an arrow marker from start_pose to reached_pose, split into a red and green part based on achieved distance
108-
static void visualizePlan(std::deque<visualization_msgs::Marker>& markers, Interface::Direction dir, bool success,
108+
static void visualizePlan(std::vector<visualization_msgs::Marker>& markers, Interface::Direction dir, bool success,
109109
const std::string& ns, const std::string& frame_id, const Eigen::Isometry3d& start_pose,
110110
const Eigen::Isometry3d& reached_pose, const Eigen::Vector3d& linear, double distance) {
111111
double linear_norm = linear.norm();
@@ -193,14 +193,17 @@ bool MoveRelative::compute(const InterfaceState& state, planning_scene::Planning
193193

194194
robot_trajectory::RobotTrajectoryPtr robot_trajectory;
195195
bool success = false;
196+
bool has_potential_collisions = false;
196197
std::string comment = "";
197198

198199
if (getJointStateFromOffset(direction, dir, jmg, scene->getCurrentStateNonConst())) {
199200
// plan to joint-space target
200201
auto result = planner_->plan(state.scene(), scene, jmg, timeout, robot_trajectory, path_constraints);
201202
success = bool(result);
202-
if (!success)
203+
if (!success) {
203204
comment = result.message;
205+
has_potential_collisions = robot_trajectory && utils::hints_at_collisions(result);
206+
}
204207
} else {
205208
// Cartesian targets require an IK reference frame
206209
const moveit::core::LinkModel* link;
@@ -292,8 +295,10 @@ bool MoveRelative::compute(const InterfaceState& state, planning_scene::Planning
292295
auto result =
293296
planner_->plan(state.scene(), *link, offset, target_eigen, jmg, timeout, robot_trajectory, path_constraints);
294297
success = bool(result);
295-
if (!success)
298+
if (!success) {
296299
comment = result.message;
300+
has_potential_collisions = robot_trajectory && utils::hints_at_collisions(result);
301+
}
297302

298303
if (robot_trajectory && robot_trajectory->getWayPointCount() > 0) { // the following requires a robot_trajectory
299304
// returned from planning
@@ -337,8 +342,11 @@ bool MoveRelative::compute(const InterfaceState& state, planning_scene::Planning
337342
robot_trajectory->reverse();
338343
solution.setTrajectory(robot_trajectory);
339344

340-
if (!success)
345+
if (!success) {
341346
solution.markAsFailure(comment);
347+
if (has_potential_collisions)
348+
utils::addCollisionMarkers(solution.markers(), *robot_trajectory, scene);
349+
}
342350
return true;
343351
}
344352
return false;

core/src/stages/move_to.cpp

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -197,14 +197,17 @@ bool MoveTo::compute(const InterfaceState& state, planning_scene::PlanningSceneP
197197
const auto& path_constraints = props.get<moveit_msgs::Constraints>("path_constraints");
198198
robot_trajectory::RobotTrajectoryPtr robot_trajectory;
199199
bool success = false;
200+
bool has_potential_collisions = false;
200201
std::string comment = "";
201202

202203
if (getJointStateGoal(goal, jmg, scene->getCurrentStateNonConst())) {
203204
// plan to joint-space target
204205
auto result = planner_->plan(state.scene(), scene, jmg, timeout, robot_trajectory, path_constraints);
205206
success = bool(result);
206-
if (!success)
207+
if (!success) {
207208
comment = result.message;
209+
has_potential_collisions = robot_trajectory && utils::hints_at_collisions(result);
210+
}
208211
} else { // Cartesian goal
209212
// Where to go?
210213
Eigen::Isometry3d target;
@@ -243,8 +246,10 @@ bool MoveTo::compute(const InterfaceState& state, planning_scene::PlanningSceneP
243246
const auto result =
244247
planner_->plan(state.scene(), *link, offset, target, jmg, timeout, robot_trajectory, path_constraints);
245248
success = bool(result);
246-
if (!success)
249+
if (!success) {
247250
comment = result.message;
251+
has_potential_collisions = robot_trajectory && utils::hints_at_collisions(result);
252+
}
248253
}
249254

250255
// store result
@@ -259,9 +264,11 @@ bool MoveTo::compute(const InterfaceState& state, planning_scene::PlanningSceneP
259264
robot_trajectory->reverse();
260265
solution.setTrajectory(robot_trajectory);
261266

262-
if (!success)
267+
if (!success) {
263268
solution.markAsFailure(comment);
264-
269+
if (has_potential_collisions)
270+
utils::addCollisionMarkers(solution.markers(), *robot_trajectory, scene);
271+
}
265272
return true;
266273
}
267274
return false;

core/src/utils.cpp

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@
3939

4040
#include <moveit/robot_state/robot_state.h>
4141
#include <moveit/planning_scene/planning_scene.h>
42+
#include <moveit/robot_trajectory/robot_trajectory.h>
43+
#include <moveit/utils/moveit_error_code.h>
4244

4345
#include <moveit/task_constructor/properties.h>
4446
#include <moveit/task_constructor/storage.h>
@@ -97,6 +99,59 @@ bool getRobotTipForFrame(const Property& tip_pose, const planning_scene::Plannin
9799
return true;
98100
}
99101

102+
void addCollisionMarkers(std::vector<visualization_msgs::Marker>& markers, const std::string& frame_id,
103+
const collision_detection::CollisionResult::ContactMap& contacts, double radius) {
104+
visualization_msgs::Marker m;
105+
m.header.frame_id = frame_id;
106+
m.ns = "collisions";
107+
m.type = visualization_msgs::Marker::SPHERE;
108+
m.action = visualization_msgs::Marker::ADD;
109+
m.pose.orientation.x = 0.0;
110+
m.pose.orientation.y = 0.0;
111+
m.pose.orientation.z = 0.0;
112+
m.pose.orientation.w = 1.0;
113+
m.scale.x = m.scale.y = m.scale.z = radius * 2.0;
114+
m.color.r = m.color.a = 1.0;
115+
116+
for (const auto& collision : contacts) {
117+
for (const auto& contact : collision.second) {
118+
m.pose.position.x = contact.pos.x();
119+
m.pose.position.y = contact.pos.y();
120+
m.pose.position.z = contact.pos.z();
121+
markers.push_back(m);
122+
}
123+
}
124+
}
125+
126+
void addCollisionMarkers(std::vector<visualization_msgs::Marker>& markers,
127+
const robot_trajectory::RobotTrajectory& trajectory,
128+
const planning_scene::PlanningSceneConstPtr& planning_scene) {
129+
std::size_t n_wp = trajectory.getWayPointCount();
130+
for (std::size_t it = 0; it < n_wp; ++it) {
131+
const moveit::core::RobotState& robot_state = trajectory.getWayPoint(it);
132+
133+
// Collision contact check
134+
collision_detection::CollisionRequest req;
135+
collision_detection::CollisionResult res;
136+
req.contacts = true;
137+
req.max_contacts = 10;
138+
139+
planning_scene->checkCollision(req, res, robot_state);
140+
141+
if (res.contact_count > 0)
142+
addCollisionMarkers(markers, planning_scene->getPlanningFrame(), res.contacts);
143+
}
144+
}
145+
146+
bool hints_at_collisions(const solvers::PlannerInterface::Result& result) {
147+
static const std::string INVALID_MOTION_PLAN_MSG = []() {
148+
moveit_msgs::MoveItErrorCodes err;
149+
err.val = moveit_msgs::MoveItErrorCodes::INVALID_MOTION_PLAN;
150+
return moveit::core::MoveItErrorCode::toString(err);
151+
}();
152+
return result.message == INVALID_MOTION_PLAN_MSG;
153+
}
154+
100155
} // namespace utils
101156
} // namespace task_constructor
102157
} // namespace moveit

0 commit comments

Comments
 (0)