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 <tf2_eigen/tf2_eigen.h>
42 #include <ros/console.h>
43 
44 namespace pick_place
45 {
47  const planning_scene::PlanningSceneConstPtr& scene,
48  const collision_detection::AllowedCollisionMatrixConstPtr& collision_matrix)
49  : ManipulationStage("approach & translate"), planning_scene_(scene), collision_matrix_(collision_matrix)
50 {
51  max_goal_count_ = GetGlobalPickPlaceParams().max_goal_count_;
52  max_fail_ = GetGlobalPickPlaceParams().max_fail_;
53  max_step_ = GetGlobalPickPlaceParams().max_step_;
54  jump_factor_ = GetGlobalPickPlaceParams().jump_factor_;
55 }
56 
57 namespace
58 {
59 bool isStateCollisionFree(const planning_scene::PlanningScene* planning_scene,
60  const collision_detection::AllowedCollisionMatrix* collision_matrix, bool verbose,
61  const trajectory_msgs::JointTrajectory* grasp_posture, moveit::core::RobotState* state,
62  const moveit::core::JointModelGroup* group, const double* joint_group_variable_values)
63 {
64  state->setJointGroupPositions(group, joint_group_variable_values);
65 
67  req.verbose = verbose;
68  req.group_name = group->getName();
69 
70  if (!grasp_posture->joint_names.empty())
71  {
72  // apply the grasp posture for the end effector (we always apply it here since it could be the case the sampler
73  // changes this posture)
74  for (std::size_t i = 0; i < grasp_posture->points.size(); ++i)
75  {
76  state->setVariablePositions(grasp_posture->joint_names, grasp_posture->points[i].positions);
78  planning_scene->checkCollision(req, res, *state, *collision_matrix);
79  if (res.collision)
80  return false;
81  }
82  }
83  else
84  {
86  planning_scene->checkCollision(req, res, *state, *collision_matrix);
87  if (res.collision)
88  return false;
89  }
90  return planning_scene->isStateFeasible(*state);
91 }
92 
93 bool samplePossibleGoalStates(const ManipulationPlanPtr& plan, const moveit::core::RobotState& reference_state,
94  double min_distance, unsigned int attempts)
95 {
96  // initialize with scene state
97  moveit::core::RobotStatePtr token_state(new moveit::core::RobotState(reference_state));
98  for (unsigned int j = 0; j < attempts; ++j)
99  {
100  double min_d = std::numeric_limits<double>::infinity();
101 
102  // Samples given the constraints, populating the joint state group
103  if (plan->goal_sampler_->sample(*token_state, plan->shared_data_->max_goal_sampling_attempts_))
104  {
105  // Check if this new sampled state is closest we've found so far
106  for (std::size_t i = 0; i < plan->possible_goal_states_.size(); ++i)
107  {
108  double d = plan->possible_goal_states_[i]->distance(*token_state, plan->shared_data_->planning_group_);
109  if (d < min_d)
110  min_d = d;
111  }
112  if (min_d >= min_distance)
113  {
114  plan->possible_goal_states_.push_back(token_state);
115  return true;
116  }
117  }
118  }
119  return false;
120 }
121 
122 // This function is called during trajectory execution, after the gripper is closed, to attach the currently gripped
123 // object
124 bool executeAttachObject(const ManipulationPlanSharedDataConstPtr& shared_plan_data,
125  const trajectory_msgs::JointTrajectory& detach_posture,
126  const plan_execution::ExecutableMotionPlan& motion_plan)
127 {
128  if (shared_plan_data->diff_attached_object_.object.id.empty())
129  {
130  // the user did not provide an object to attach, so just return successfully
131  return true;
132  }
133 
134  ROS_DEBUG_NAMED("manipulation", "Applying attached object diff to maintained planning scene (attaching/detaching "
135  "object to end effector)");
136  bool ok = false;
137  {
139  moveit_msgs::AttachedCollisionObject msg = shared_plan_data->diff_attached_object_;
140  // remember the configuration of the gripper before the grasp;
141  // this configuration will be set again when releasing the object
142  msg.detach_posture = detach_posture;
143  ok = ps->processAttachedCollisionObjectMsg(msg);
144  }
145  motion_plan.planning_scene_monitor_->triggerSceneUpdateEvent(
149  return ok;
150 }
151 
152 // Add the close end effector trajectory to the overall plan (after the approach trajectory, before the retreat)
153 void addGripperTrajectory(const ManipulationPlanPtr& plan,
154  const collision_detection::AllowedCollisionMatrixConstPtr& collision_matrix,
155  const std::string& name)
156 {
157  // Check if a "closed" end effector configuration was specified
158  if (!plan->retreat_posture_.joint_names.empty())
159  {
160  moveit::core::RobotStatePtr ee_closed_state(
161  new moveit::core::RobotState(plan->trajectories_.back().trajectory_->getLastWayPoint()));
162 
163  robot_trajectory::RobotTrajectoryPtr ee_closed_traj(new robot_trajectory::RobotTrajectory(
164  ee_closed_state->getRobotModel(), plan->shared_data_->end_effector_group_->getName()));
165  ee_closed_traj->setRobotTrajectoryMsg(*ee_closed_state, plan->retreat_posture_);
166  // If user has defined a time for it's gripper movement time, don't add the
167  // DEFAULT_GRASP_POSTURE_COMPLETION_DURATION
168  if (!plan->retreat_posture_.points.empty() &&
169  plan->retreat_posture_.points.back().time_from_start > ros::Duration(0.0))
170  {
171  ee_closed_traj->addPrefixWayPoint(ee_closed_state, 0.0);
172  }
173  else
174  { // Do what was done before
175  ROS_INFO_STREAM("Adding default duration of " << PickPlace::DEFAULT_GRASP_POSTURE_COMPLETION_DURATION
176  << " seconds to the grasp closure time. Assign time_from_start to "
177  << "your trajectory to avoid this.");
178  ee_closed_traj->addPrefixWayPoint(ee_closed_state, PickPlace::DEFAULT_GRASP_POSTURE_COMPLETION_DURATION);
179  }
180 
181  plan_execution::ExecutableTrajectory et(ee_closed_traj, name);
182 
183  // Add a callback to attach the object to the EE after closing the gripper
184  et.effect_on_success_ = [plan](const plan_execution::ExecutableMotionPlan* motion_plan) {
185  return executeAttachObject(plan->shared_data_, plan->approach_posture_, *motion_plan);
186  };
187  et.allowed_collision_matrix_ = collision_matrix;
188  plan->trajectories_.push_back(et);
189  }
190  else
191  {
192  ROS_WARN_NAMED("manipulation", "No joint states of grasp postures have been defined in the pick place action.");
193  }
194 }
195 
196 } // namespace
197 
198 bool ApproachAndTranslateStage::evaluate(const ManipulationPlanPtr& plan) const
199 {
200  const moveit::core::JointModelGroup* jmg = plan->shared_data_->planning_group_;
201  // compute what the maximum distance reported between any two states in the planning group could be, and keep 1% of
202  // that;
203  // this is the minimum distance between sampled goal states
204  const double min_distance = 0.01 * jmg->getMaximumExtent();
205 
206  // convert approach direction and retreat direction to Eigen structures
207  Eigen::Vector3d approach_direction, retreat_direction;
208  tf2::fromMsg(plan->approach_.direction.vector, approach_direction);
209  tf2::fromMsg(plan->retreat_.direction.vector, retreat_direction);
210 
211  // if translation vectors are specified in the frame of the ik link name, then we assume the frame is local;
212  // otherwise, the frame is global
213  bool approach_direction_is_global_frame = !moveit::core::Transforms::sameFrame(
214  plan->approach_.direction.header.frame_id, plan->shared_data_->ik_link_->getName());
215  bool retreat_direction_is_global_frame = !moveit::core::Transforms::sameFrame(
216  plan->retreat_.direction.header.frame_id, plan->shared_data_->ik_link_->getName());
217 
218  // transform the input vectors in accordance to frame specified in the header;
219  if (approach_direction_is_global_frame)
220  // getFrameTransform() returns a valid isometry by contract
221  approach_direction =
222  planning_scene_->getFrameTransform(plan->approach_.direction.header.frame_id).linear() * approach_direction;
223  if (retreat_direction_is_global_frame)
224  // getFrameTransform() returns a valid isometry by contract
225  retreat_direction =
226  planning_scene_->getFrameTransform(plan->retreat_.direction.header.frame_id).linear() * retreat_direction;
227 
228  // state validity checking during the approach must ensure that the gripper posture is that for pre-grasping
229  moveit::core::GroupStateValidityCallbackFn approach_valid_callback =
230  [scene = planning_scene_.get(), acm = collision_matrix_.get(), verbose = this->verbose_,
231  approach_posture = &plan->approach_posture_](moveit::core::RobotState* robot_state,
232  const moveit::core::JointModelGroup* joint_group,
233  const double* joint_group_variable_values) {
234  return isStateCollisionFree(scene, acm, verbose, approach_posture, robot_state, joint_group,
235  joint_group_variable_values);
236  };
237  plan->goal_sampler_->setVerbose(verbose_);
238  std::size_t attempted_possible_goal_states = 0;
239  do // continously sample possible goal states
240  {
241  for (std::size_t i = attempted_possible_goal_states; i < plan->possible_goal_states_.size() && !signal_stop_;
242  ++i, ++attempted_possible_goal_states)
243  {
244  // if we are trying to get as close as possible to the goal (maximum one meter)
245  if (plan->shared_data_->minimize_object_distance_)
246  {
247  static const double MAX_CLOSE_UP_DIST = 1.0;
248  moveit::core::RobotStatePtr close_up_state(new moveit::core::RobotState(*plan->possible_goal_states_[i]));
249  std::vector<moveit::core::RobotStatePtr> close_up_states;
251  close_up_state.get(), plan->shared_data_->planning_group_, close_up_states, plan->shared_data_->ik_link_,
252  approach_direction, approach_direction_is_global_frame, MAX_CLOSE_UP_DIST,
253  moveit::core::MaxEEFStep(max_step_), moveit::core::JumpThreshold(jump_factor_), approach_valid_callback);
254  // if progress towards the object was made, update the desired goal state
255  if (d_close_up > 0.0 && close_up_states.size() > 1)
256  *plan->possible_goal_states_[i] = *close_up_states[close_up_states.size() - 2];
257  }
258 
259  // try to compute a straight line path that arrives at the goal using the specified approach direction
260  moveit::core::RobotStatePtr first_approach_state(new moveit::core::RobotState(*plan->possible_goal_states_[i]));
261 
262  std::vector<moveit::core::RobotStatePtr> approach_states;
264  first_approach_state.get(), plan->shared_data_->planning_group_, approach_states,
265  plan->shared_data_->ik_link_, -approach_direction, approach_direction_is_global_frame,
266  plan->approach_.desired_distance, moveit::core::MaxEEFStep(max_step_),
267  moveit::core::JumpThreshold(jump_factor_), approach_valid_callback);
268 
269  // if we were able to follow the approach direction for sufficient length, try to compute a retreat direction
270  if (d_approach > plan->approach_.min_distance && !signal_stop_)
271  {
272  if (plan->retreat_.desired_distance > 0.0)
273  {
274  // construct a planning scene that is just a diff on top of our actual planning scene
275  planning_scene::PlanningScenePtr planning_scene_after_approach = planning_scene_->diff();
276 
277  // assume the current state of the diff world is the one we plan to reach
278  planning_scene_after_approach->getCurrentStateNonConst() = *plan->possible_goal_states_[i];
279 
280  // apply the difference message to this world that virtually attaches the object we are manipulating
281  planning_scene_after_approach->processAttachedCollisionObjectMsg(plan->shared_data_->diff_attached_object_);
282 
283  // state validity checking during the retreat after the grasp must ensure the gripper posture is that of the
284  // actual grasp
285  moveit::core::GroupStateValidityCallbackFn retreat_valid_callback =
286  [scene = planning_scene_after_approach.get(), acm = collision_matrix_.get(), verbose = verbose_,
287  retreat_posture = &plan->retreat_posture_](moveit::core::RobotState* robot_state,
288  const moveit::core::JointModelGroup* joint_group,
289  const double* joint_group_variable_values) {
290  return isStateCollisionFree(scene, acm, verbose, retreat_posture, robot_state, joint_group,
291  joint_group_variable_values);
292  };
293 
294  // try to compute a straight line path that moves from the goal in a desired direction
295  moveit::core::RobotStatePtr last_retreat_state(
296  new moveit::core::RobotState(planning_scene_after_approach->getCurrentState()));
297  std::vector<moveit::core::RobotStatePtr> retreat_states;
299  last_retreat_state.get(), plan->shared_data_->planning_group_, retreat_states,
300  plan->shared_data_->ik_link_, retreat_direction, retreat_direction_is_global_frame,
301  plan->retreat_.desired_distance, moveit::core::MaxEEFStep(max_step_),
302  moveit::core::JumpThreshold(jump_factor_), retreat_valid_callback);
303 
304  // if sufficient progress was made in the desired direction, we have a goal state that we can consider for
305  // future stages
306  if (d_retreat > plan->retreat_.min_distance && !signal_stop_)
307  {
308  // Create approach trajectory
309  std::reverse(approach_states.begin(), approach_states.end());
310  robot_trajectory::RobotTrajectoryPtr approach_traj(new robot_trajectory::RobotTrajectory(
311  planning_scene_->getRobotModel(), plan->shared_data_->planning_group_->getName()));
312  for (const moveit::core::RobotStatePtr& approach_state : approach_states)
313  approach_traj->addSuffixWayPoint(approach_state, 0.0);
314 
315  // Create retreat trajectory
316  robot_trajectory::RobotTrajectoryPtr retreat_traj(new robot_trajectory::RobotTrajectory(
317  planning_scene_->getRobotModel(), plan->shared_data_->planning_group_->getName()));
318  for (const moveit::core::RobotStatePtr& retreat_state : retreat_states)
319  retreat_traj->addSuffixWayPoint(retreat_state, 0.0);
320 
321  // Add timestamps to approach|retreat trajectories
322  time_param_.computeTimeStamps(*approach_traj);
323  time_param_.computeTimeStamps(*retreat_traj);
324 
325  // Convert approach trajectory to an executable trajectory
326  plan_execution::ExecutableTrajectory et_approach(approach_traj, "approach");
327  et_approach.allowed_collision_matrix_ = collision_matrix_;
328  plan->trajectories_.push_back(et_approach);
329 
330  // Add gripper close trajectory
331  addGripperTrajectory(plan, collision_matrix_, "grasp");
332 
333  // Convert retreat trajectory to an executable trajectory
334  plan_execution::ExecutableTrajectory et_retreat(retreat_traj, "retreat");
335  et_retreat.allowed_collision_matrix_ = collision_matrix_;
336  plan->trajectories_.push_back(et_retreat);
337 
338  plan->approach_state_ = approach_states.front();
339  return true;
340  }
341  }
342  else // No retreat was specified, so package up approach and grip trajectories.
343  {
344  // Reset the approach_state_ RobotStatePtr so that we can retry computing the cartesian path
345  plan->approach_state_.swap(first_approach_state);
346 
347  // Create approach trajectory
348  std::reverse(approach_states.begin(), approach_states.end());
349  robot_trajectory::RobotTrajectoryPtr approach_traj(new robot_trajectory::RobotTrajectory(
350  planning_scene_->getRobotModel(), plan->shared_data_->planning_group_->getName()));
351  for (const moveit::core::RobotStatePtr& approach_state : approach_states)
352  approach_traj->addSuffixWayPoint(approach_state, 0.0);
353 
354  // Add timestamps to approach trajectories
355  time_param_.computeTimeStamps(*approach_traj);
356 
357  // Convert approach trajectory to an executable trajectory
358  plan_execution::ExecutableTrajectory et_approach(approach_traj, "approach");
359  et_approach.allowed_collision_matrix_ = collision_matrix_;
360  plan->trajectories_.push_back(et_approach);
361 
362  // Add gripper close trajectory
363  addGripperTrajectory(plan, collision_matrix_, "grasp");
364 
365  plan->approach_state_ = approach_states.front();
366 
367  return true;
368  }
369  }
370  }
371  } while (plan->possible_goal_states_.size() < max_goal_count_ && !signal_stop_ &&
372  samplePossibleGoalStates(plan, planning_scene_->getCurrentState(), min_distance, max_fail_));
373 
374  plan->error_code_.val = moveit_msgs::MoveItErrorCodes::PLANNING_FAILED;
375 
376  return false;
377 }
378 } // namespace pick_place
moveit::core::GroupStateValidityCallbackFn
boost::function< bool(RobotState *robot_state, const JointModelGroup *joint_group, const double *joint_group_variable_values)> GroupStateValidityCallbackFn
plan_execution::ExecutableMotionPlan::planning_scene_monitor_
planning_scene_monitor::PlanningSceneMonitorPtr planning_scene_monitor_
pick_place
Definition: approach_and_translate_stage.h:43
moveit::core::RobotState::setVariablePositions
void setVariablePositions(const double *position)
pick_place::PickPlaceParams::max_fail_
unsigned int max_fail_
Definition: pick_place_params.h:110
moveit::core::JumpThreshold
tf2_eigen.h
tf2::fromMsg
void fromMsg(const A &, B &b)
planning_scene::PlanningScene
moveit::core::RobotState
robot_trajectory::RobotTrajectory
pick_place.h
collision_detection::CollisionRequest
ok
ROSCPP_DECL bool ok()
planning_scene_monitor::PlanningSceneMonitor::SceneUpdateType
SceneUpdateType
planning_scene_monitor::LockedPlanningSceneRW
moveit::core::JointModelGroup::getName
const std::string & getName() const
console.h
collision_detection::AllowedCollisionMatrix
ROS_DEBUG_NAMED
#define ROS_DEBUG_NAMED(name,...)
collision_detection::CollisionResult
pick_place::PickPlaceParams::max_goal_count_
unsigned int max_goal_count_
Definition: pick_place_params.h:109
pick_place::PickPlaceParams::max_step_
double max_step_
Definition: pick_place_params.h:111
planning_scene_monitor::PlanningSceneMonitor::UPDATE_STATE
UPDATE_STATE
collision_detection::CollisionRequest::verbose
bool verbose
collision_detection::CollisionRequest::group_name
std::string group_name
moveit::core::MaxEEFStep
d
d
ROS_INFO_STREAM
#define ROS_INFO_STREAM(args)
plan_execution::ExecutableTrajectory
moveit::core::Transforms::sameFrame
static bool sameFrame(const std::string &frame1, const std::string &frame2)
moveit::core::CartesianInterpolator::computeCartesianPath
static double computeCartesianPath(RobotState *start_state, const JointModelGroup *group, std::vector< std::shared_ptr< RobotState >> &traj, const LinkModel *link, const Eigen::Isometry3d &target, bool global_reference_frame, const MaxEEFStep &max_step, const JumpThreshold &jump_threshold, const GroupStateValidityCallbackFn &validCallback=GroupStateValidityCallbackFn(), const kinematics::KinematicsQueryOptions &options=kinematics::KinematicsQueryOptions(), const Eigen::Isometry3d &link_offset=Eigen::Isometry3d::Identity())
approach_and_translate_stage.h
plan_execution::ExecutableMotionPlan
ROS_WARN_NAMED
#define ROS_WARN_NAMED(name,...)
moveit::core::JointModelGroup
planning_scene_monitor::PlanningSceneMonitor::UPDATE_GEOMETRY
UPDATE_GEOMETRY
cartesian_interpolator.h
collision_detection::CollisionResult::collision
bool collision
pick_place::PickPlaceParams::jump_factor_
double jump_factor_
Definition: pick_place_params.h:112
pick_place::ApproachAndTranslateStage::ApproachAndTranslateStage
ApproachAndTranslateStage(const planning_scene::PlanningSceneConstPtr &scene, const collision_detection::AllowedCollisionMatrixConstPtr &collision_matrix)
Definition: approach_and_translate_stage.cpp:78
pick_place::GetGlobalPickPlaceParams
const PickPlaceParams & GetGlobalPickPlaceParams()
Definition: pick_place_params.cpp:81
trajectory_tools.h
moveit::core::RobotState::setJointGroupPositions
void setJointGroupPositions(const std::string &joint_group_name, const double *gstate)
planning_scene
ros::Duration
moveit::core::JointModelGroup::getMaximumExtent
double getMaximumExtent() const
verbose
bool verbose


manipulation
Author(s): Ioan Sucan , Sachin Chitta
autogenerated on Fri May 3 2024 02:29:51