approach_and_translate_stage.cpp
Go to the documentation of this file.
1 /*********************************************************************
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2012, Willow Garage, Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above
14  * copyright notice, this list of conditions and the following
15  * disclaimer in the documentation and/or other materials provided
16  * with the distribution.
17  * * Neither the name of Willow Garage nor the names of its
18  * contributors may be used to endorse or promote products derived
19  * from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *********************************************************************/
34 
35 /* Author: Ioan Sucan */
36 
41 #include <ros/console.h>
42 
43 namespace pick_place
44 {
46  const planning_scene::PlanningSceneConstPtr& scene,
47  const collision_detection::AllowedCollisionMatrixConstPtr& collision_matrix)
48  : ManipulationStage("approach & translate"), planning_scene_(scene), collision_matrix_(collision_matrix)
49 {
54 }
55 
56 namespace
57 {
58 bool isStateCollisionFree(const planning_scene::PlanningScene* planning_scene,
59  const collision_detection::AllowedCollisionMatrix* collision_matrix, bool verbose,
60  const trajectory_msgs::JointTrajectory* grasp_posture, robot_state::RobotState* state,
61  const robot_state::JointModelGroup* group, const double* joint_group_variable_values)
62 {
63  state->setJointGroupPositions(group, joint_group_variable_values);
64 
66  req.verbose = verbose;
67  req.group_name = group->getName();
68 
69  if (grasp_posture->joint_names.size() > 0)
70  {
71  // apply the grasp posture for the end effector (we always apply it here since it could be the case the sampler
72  // changes this posture)
73  for (std::size_t i = 0; i < grasp_posture->points.size(); ++i)
74  {
75  state->setVariablePositions(grasp_posture->joint_names, grasp_posture->points[i].positions);
77  planning_scene->checkCollision(req, res, *state, *collision_matrix);
78  if (res.collision)
79  return false;
80  }
81  }
82  else
83  {
85  planning_scene->checkCollision(req, res, *state, *collision_matrix);
86  if (res.collision)
87  return false;
88  }
89  return planning_scene->isStateFeasible(*state);
90 }
91 
92 bool samplePossibleGoalStates(const ManipulationPlanPtr& plan, const robot_state::RobotState& reference_state,
93  double min_distance, unsigned int attempts)
94 {
95  // initialize with scene state
96  robot_state::RobotStatePtr token_state(new robot_state::RobotState(reference_state));
97  for (unsigned int j = 0; j < attempts; ++j)
98  {
99  double min_d = std::numeric_limits<double>::infinity();
100 
101  // Samples given the constraints, populating the joint state group
102  if (plan->goal_sampler_->sample(*token_state, plan->shared_data_->max_goal_sampling_attempts_))
103  {
104  // Check if this new sampled state is closest we've found so far
105  for (std::size_t i = 0; i < plan->possible_goal_states_.size(); ++i)
106  {
107  double d = plan->possible_goal_states_[i]->distance(*token_state, plan->shared_data_->planning_group_);
108  if (d < min_d)
109  min_d = d;
110  }
111  if (min_d >= min_distance)
112  {
113  plan->possible_goal_states_.push_back(token_state);
114  return true;
115  }
116  }
117  }
118  return false;
119 }
120 
121 // This function is called during trajectory execution, after the gripper is closed, to attach the currently gripped
122 // object
123 bool executeAttachObject(const ManipulationPlanSharedDataConstPtr& shared_plan_data,
124  const trajectory_msgs::JointTrajectory& detach_posture,
125  const plan_execution::ExecutableMotionPlan* motion_plan)
126 {
127  if (shared_plan_data->diff_attached_object_.object.id.empty())
128  {
129  // the user did not provide an object to attach, so just return successfully
130  return true;
131  }
132 
133  ROS_DEBUG_NAMED("manipulation", "Applying attached object diff to maintained planning scene (attaching/detaching "
134  "object to end effector)");
135  bool ok = false;
136  {
138  moveit_msgs::AttachedCollisionObject msg = shared_plan_data->diff_attached_object_;
139  // remember the configuration of the gripper before the grasp;
140  // this configuration will be set again when releasing the object
141  msg.detach_posture = detach_posture;
142  ok = ps->processAttachedCollisionObjectMsg(msg);
143  }
144  motion_plan->planning_scene_monitor_->triggerSceneUpdateEvent(
148  return ok;
149 }
150 
151 // Add the close end effector trajectory to the overall plan (after the approach trajectory, before the retreat)
152 void addGripperTrajectory(const ManipulationPlanPtr& plan,
153  const collision_detection::AllowedCollisionMatrixConstPtr& collision_matrix,
154  const std::string& name)
155 {
156  // Check if a "closed" end effector configuration was specified
157  if (!plan->retreat_posture_.joint_names.empty())
158  {
159  robot_state::RobotStatePtr ee_closed_state(
160  new robot_state::RobotState(plan->trajectories_.back().trajectory_->getLastWayPoint()));
161 
162  robot_trajectory::RobotTrajectoryPtr ee_closed_traj(new robot_trajectory::RobotTrajectory(
163  ee_closed_state->getRobotModel(), plan->shared_data_->end_effector_group_->getName()));
164  ee_closed_traj->setRobotTrajectoryMsg(*ee_closed_state, plan->retreat_posture_);
165  // If user has defined a time for it's gripper movement time, don't add the
166  // DEFAULT_GRASP_POSTURE_COMPLETION_DURATION
167  if (plan->retreat_posture_.points.size() > 0 &&
168  plan->retreat_posture_.points.back().time_from_start > ros::Duration(0.0))
169  {
170  ee_closed_traj->addPrefixWayPoint(ee_closed_state, 0.0);
171  }
172  else
173  { // Do what was done before
174  ee_closed_traj->addPrefixWayPoint(ee_closed_state, PickPlace::DEFAULT_GRASP_POSTURE_COMPLETION_DURATION);
175  }
176 
177  plan_execution::ExecutableTrajectory et(ee_closed_traj, name);
178 
179  // Add a callback to attach the object to the EE after closing the gripper
180  et.effect_on_success_ = boost::bind(&executeAttachObject, plan->shared_data_, plan->approach_posture_, _1);
181  et.allowed_collision_matrix_ = collision_matrix;
182  plan->trajectories_.push_back(et);
183  }
184  else
185  {
186  ROS_WARN_NAMED("manipulation", "No joint states of grasp postures have been defined in the pick place action.");
187  }
188 }
189 
190 } // annonymous namespace
191 
192 bool ApproachAndTranslateStage::evaluate(const ManipulationPlanPtr& plan) const
193 {
194  const robot_model::JointModelGroup* jmg = plan->shared_data_->planning_group_;
195  // compute what the maximum distance reported between any two states in the planning group could be, and keep 1% of
196  // that;
197  // this is the minimum distance between sampled goal states
198  const double min_distance = 0.01 * jmg->getMaximumExtent();
199 
200  // convert approach direction and retreat direction to Eigen structures
201  Eigen::Vector3d approach_direction, retreat_direction;
202  tf::vectorMsgToEigen(plan->approach_.direction.vector, approach_direction);
203  tf::vectorMsgToEigen(plan->retreat_.direction.vector, retreat_direction);
204 
205  // if translation vectors are specified in the frame of the ik link name, then we assume the frame is local;
206  // otherwise, the frame is global
207  bool approach_direction_is_global_frame = !robot_state::Transforms::sameFrame(
208  plan->approach_.direction.header.frame_id, plan->shared_data_->ik_link_->getName());
209  bool retreat_direction_is_global_frame = !robot_state::Transforms::sameFrame(plan->retreat_.direction.header.frame_id,
210  plan->shared_data_->ik_link_->getName());
211 
212  // transform the input vectors in accordance to frame specified in the header;
213  if (approach_direction_is_global_frame)
214  approach_direction =
215  planning_scene_->getFrameTransform(plan->approach_.direction.header.frame_id).rotation() * approach_direction;
216  if (retreat_direction_is_global_frame)
217  retreat_direction =
218  planning_scene_->getFrameTransform(plan->retreat_.direction.header.frame_id).rotation() * retreat_direction;
219 
220  // state validity checking during the approach must ensure that the gripper posture is that for pre-grasping
221  robot_state::GroupStateValidityCallbackFn approach_validCallback =
222  boost::bind(&isStateCollisionFree, planning_scene_.get(), collision_matrix_.get(), verbose_,
223  &plan->approach_posture_, _1, _2, _3);
224  plan->goal_sampler_->setVerbose(verbose_);
225  std::size_t attempted_possible_goal_states = 0;
226  do // continously sample possible goal states
227  {
228  for (std::size_t i = attempted_possible_goal_states; i < plan->possible_goal_states_.size() && !signal_stop_;
229  ++i, ++attempted_possible_goal_states)
230  {
231  // if we are trying to get as close as possible to the goal (maximum one meter)
232  if (plan->shared_data_->minimize_object_distance_)
233  {
234  static const double MAX_CLOSE_UP_DIST = 1.0;
235  robot_state::RobotStatePtr close_up_state(new robot_state::RobotState(*plan->possible_goal_states_[i]));
236  std::vector<robot_state::RobotStatePtr> close_up_states;
237  double d_close_up = close_up_state->computeCartesianPath(
238  plan->shared_data_->planning_group_, close_up_states, plan->shared_data_->ik_link_, approach_direction,
239  approach_direction_is_global_frame, MAX_CLOSE_UP_DIST, max_step_, jump_factor_, approach_validCallback);
240  // if progress towards the object was made, update the desired goal state
241  if (d_close_up > 0.0 && close_up_states.size() > 1)
242  *plan->possible_goal_states_[i] = *close_up_states[close_up_states.size() - 2];
243  }
244 
245  // try to compute a straight line path that arrives at the goal using the specified approach direction
246  robot_state::RobotStatePtr first_approach_state(new robot_state::RobotState(*plan->possible_goal_states_[i]));
247 
248  std::vector<robot_state::RobotStatePtr> approach_states;
249  double d_approach = first_approach_state->computeCartesianPath(
250  plan->shared_data_->planning_group_, approach_states, plan->shared_data_->ik_link_, -approach_direction,
251  approach_direction_is_global_frame, plan->approach_.desired_distance, max_step_, jump_factor_,
252  approach_validCallback);
253 
254  // if we were able to follow the approach direction for sufficient length, try to compute a retreat direction
255  if (d_approach > plan->approach_.min_distance && !signal_stop_)
256  {
257  if (plan->retreat_.desired_distance > 0.0)
258  {
259  // construct a planning scene that is just a diff on top of our actual planning scene
260  planning_scene::PlanningScenePtr planning_scene_after_approach = planning_scene_->diff();
261 
262  // assume the current state of the diff world is the one we plan to reach
263  planning_scene_after_approach->getCurrentStateNonConst() = *plan->possible_goal_states_[i];
264 
265  // apply the difference message to this world that virtually attaches the object we are manipulating
266  planning_scene_after_approach->processAttachedCollisionObjectMsg(plan->shared_data_->diff_attached_object_);
267 
268  // state validity checking during the retreat after the grasp must ensure the gripper posture is that of the
269  // actual grasp
270  robot_state::GroupStateValidityCallbackFn retreat_validCallback =
271  boost::bind(&isStateCollisionFree, planning_scene_after_approach.get(), collision_matrix_.get(), verbose_,
272  &plan->retreat_posture_, _1, _2, _3);
273 
274  // try to compute a straight line path that moves from the goal in a desired direction
275  robot_state::RobotStatePtr last_retreat_state(
276  new robot_state::RobotState(planning_scene_after_approach->getCurrentState()));
277  std::vector<robot_state::RobotStatePtr> retreat_states;
278  double d_retreat = last_retreat_state->computeCartesianPath(
279  plan->shared_data_->planning_group_, retreat_states, plan->shared_data_->ik_link_, retreat_direction,
280  retreat_direction_is_global_frame, plan->retreat_.desired_distance, max_step_, jump_factor_,
281  retreat_validCallback);
282 
283  // if sufficient progress was made in the desired direction, we have a goal state that we can consider for
284  // future stages
285  if (d_retreat > plan->retreat_.min_distance && !signal_stop_)
286  {
287  // Create approach trajectory
288  std::reverse(approach_states.begin(), approach_states.end());
289  robot_trajectory::RobotTrajectoryPtr approach_traj(new robot_trajectory::RobotTrajectory(
290  planning_scene_->getRobotModel(), plan->shared_data_->planning_group_->getName()));
291  for (std::size_t k = 0; k < approach_states.size(); ++k)
292  approach_traj->addSuffixWayPoint(approach_states[k], 0.0);
293 
294  // Create retreat trajectory
295  robot_trajectory::RobotTrajectoryPtr retreat_traj(new robot_trajectory::RobotTrajectory(
296  planning_scene_->getRobotModel(), plan->shared_data_->planning_group_->getName()));
297  for (std::size_t k = 0; k < retreat_states.size(); ++k)
298  retreat_traj->addSuffixWayPoint(retreat_states[k], 0.0);
299 
300  // Add timestamps to approach|retreat trajectories
301  time_param_.computeTimeStamps(*approach_traj);
302  time_param_.computeTimeStamps(*retreat_traj);
303 
304  // Convert approach trajectory to an executable trajectory
305  plan_execution::ExecutableTrajectory et_approach(approach_traj, "approach");
307  plan->trajectories_.push_back(et_approach);
308 
309  // Add gripper close trajectory
310  addGripperTrajectory(plan, collision_matrix_, "grasp");
311 
312  // Convert retreat trajectory to an executable trajectory
313  plan_execution::ExecutableTrajectory et_retreat(retreat_traj, "retreat");
315  plan->trajectories_.push_back(et_retreat);
316 
317  plan->approach_state_ = approach_states.front();
318  return true;
319  }
320  }
321  else // No retreat was specified, so package up approach and grip trajectories.
322  {
323  // Reset the approach_state_ RobotStatePtr so that we can retry computing the cartesian path
324  plan->approach_state_.swap(first_approach_state);
325 
326  // Create approach trajectory
327  std::reverse(approach_states.begin(), approach_states.end());
328  robot_trajectory::RobotTrajectoryPtr approach_traj(new robot_trajectory::RobotTrajectory(
329  planning_scene_->getRobotModel(), plan->shared_data_->planning_group_->getName()));
330  for (std::size_t k = 0; k < approach_states.size(); ++k)
331  approach_traj->addSuffixWayPoint(approach_states[k], 0.0);
332 
333  // Add timestamps to approach trajectories
334  time_param_.computeTimeStamps(*approach_traj);
335 
336  // Convert approach trajectory to an executable trajectory
337  plan_execution::ExecutableTrajectory et_approach(approach_traj, "approach");
339  plan->trajectories_.push_back(et_approach);
340 
341  // Add gripper close trajectory
342  addGripperTrajectory(plan, collision_matrix_, "grasp");
343 
344  plan->approach_state_ = approach_states.front();
345 
346  return true;
347  }
348  }
349  }
350  } while (plan->possible_goal_states_.size() < max_goal_count_ && !signal_stop_ &&
351  samplePossibleGoalStates(plan, planning_scene_->getCurrentState(), min_distance, max_fail_));
352 
353  plan->error_code_.val = moveit_msgs::MoveItErrorCodes::PLANNING_FAILED;
354 
355  return false;
356 }
357 }
d
collision_detection::AllowedCollisionMatrixConstPtr allowed_collision_matrix_
#define ROS_WARN_NAMED(name,...)
collision_detection::AllowedCollisionMatrixConstPtr collision_matrix_
trajectory_processing::IterativeParabolicTimeParameterization time_param_
const PickPlaceParams & GetGlobalPickPlaceParams()
ApproachAndTranslateStage(const planning_scene::PlanningSceneConstPtr &scene, const collision_detection::AllowedCollisionMatrixConstPtr &collision_matrix)
virtual bool evaluate(const ManipulationPlanPtr &plan) const
#define ROS_DEBUG_NAMED(name,...)
bool verbose
void vectorMsgToEigen(const geometry_msgs::Vector3 &m, Eigen::Vector3d &e)
planning_scene_monitor::PlanningSceneMonitorPtr planning_scene_monitor_
void checkCollision(const collision_detection::CollisionRequest &req, collision_detection::CollisionResult &res)
bool isStateFeasible(const moveit_msgs::RobotState &state, bool verbose=false) const
planning_scene::PlanningSceneConstPtr planning_scene_
bool computeTimeStamps(robot_trajectory::RobotTrajectory &trajectory, const double max_velocity_scaling_factor=1.0, const double max_acceleration_scaling_factor=1.0) const
boost::function< bool(const ExecutableMotionPlan *)> effect_on_success_
static const double DEFAULT_GRASP_POSTURE_COMPLETION_DURATION
Definition: pick_place.h:116


manipulation
Author(s): Ioan Sucan , Sachin Chitta
autogenerated on Sun Jan 21 2018 03:55:51