plan_execution.cpp
Go to the documentation of this file.
00001 /*********************************************************************
00002 * Software License Agreement (BSD License)
00003 *
00004 *  Copyright (c) 2012, Willow Garage, Inc.
00005 *  All rights reserved.
00006 *
00007 *  Redistribution and use in source and binary forms, with or without
00008 *  modification, are permitted provided that the following conditions
00009 *  are met:
00010 *
00011 *   * Redistributions of source code must retain the above copyright
00012 *     notice, this list of conditions and the following disclaimer.
00013 *   * Redistributions in binary form must reproduce the above
00014 *     copyright notice, this list of conditions and the following
00015 *     disclaimer in the documentation and/or other materials provided
00016 *     with the distribution.
00017 *   * Neither the name of the Willow Garage nor the names of its
00018 *     contributors may be used to endorse or promote products derived
00019 *     from this software without specific prior written permission.
00020 *
00021 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00022 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00023 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00024 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00025 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00026 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00027 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00028 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00029 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00030 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00031 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00032 *  POSSIBILITY OF SUCH DAMAGE.
00033 *********************************************************************/
00034 
00035 /* Author: Ioan Sucan */
00036 
00037 #include <moveit/plan_execution/plan_execution.h>
00038 #include <moveit/robot_state/conversions.h>
00039 #include <moveit/trajectory_processing/trajectory_tools.h>
00040 #include <moveit/collision_detection/collision_tools.h>
00041 #include <boost/algorithm/string/join.hpp>
00042 
00043 #include <dynamic_reconfigure/server.h>
00044 #include <moveit_ros_planning/PlanExecutionDynamicReconfigureConfig.h>
00045 
00046 namespace plan_execution
00047 {
00048 using namespace moveit_ros_planning;
00049 
00050 class PlanExecution::DynamicReconfigureImpl
00051 {
00052 public:
00053 
00054   DynamicReconfigureImpl(PlanExecution *owner) : owner_(owner),
00055                                                  dynamic_reconfigure_server_(ros::NodeHandle("~/plan_execution"))
00056   {
00057     dynamic_reconfigure_server_.setCallback(boost::bind(&DynamicReconfigureImpl::dynamicReconfigureCallback, this, _1, _2));
00058   }
00059 
00060 private:
00061 
00062   void dynamicReconfigureCallback(PlanExecutionDynamicReconfigureConfig &config, uint32_t level)
00063   {
00064     owner_->setMaxReplanAttempts(config.max_replan_attempts);
00065     owner_->setTrajectoryStateRecordingFrequency(config.record_trajectory_state_frequency);
00066   }
00067 
00068   PlanExecution *owner_;
00069   dynamic_reconfigure::Server<PlanExecutionDynamicReconfigureConfig> dynamic_reconfigure_server_;
00070 };
00071 
00072 }
00073 
00074 plan_execution::PlanExecution::PlanExecution(const planning_scene_monitor::PlanningSceneMonitorPtr &planning_scene_monitor,
00075                                              const trajectory_execution_manager::TrajectoryExecutionManagerPtr& trajectory_execution) :
00076   node_handle_("~"), planning_scene_monitor_(planning_scene_monitor),
00077   trajectory_execution_manager_(trajectory_execution)
00078 {
00079   if (!trajectory_execution_manager_)
00080     trajectory_execution_manager_.reset(new trajectory_execution_manager::TrajectoryExecutionManager(planning_scene_monitor_->getRobotModel()));
00081 
00082   default_max_replan_attempts_ = 5;
00083 
00084   preempt_requested_ = false;
00085   new_scene_update_ = false;
00086 
00087   // we want to be notified when new information is available
00088   planning_scene_monitor_->addUpdateCallback(boost::bind(&PlanExecution::planningSceneUpdatedCallback, this, _1));
00089 
00090   // start the dynamic-reconfigure server
00091   reconfigure_impl_ = new DynamicReconfigureImpl(this);
00092 }
00093 
00094 plan_execution::PlanExecution::~PlanExecution()
00095 {
00096   delete reconfigure_impl_;
00097 }
00098 
00099 void plan_execution::PlanExecution::stop()
00100 {
00101   preempt_requested_ = true;
00102 }
00103 
00104 std::string plan_execution::PlanExecution::getErrorCodeString(const moveit_msgs::MoveItErrorCodes& error_code)
00105 {
00106   if (error_code.val == moveit_msgs::MoveItErrorCodes::SUCCESS)
00107     return "Success";
00108   else
00109     if (error_code.val == moveit_msgs::MoveItErrorCodes::INVALID_GROUP_NAME)
00110       return "Invalid group name";
00111     else
00112       if (error_code.val == moveit_msgs::MoveItErrorCodes::PLANNING_FAILED)
00113         return "Planning failed.";
00114       else
00115         if (error_code.val == moveit_msgs::MoveItErrorCodes::INVALID_MOTION_PLAN)
00116           return "Invalid motion plan";
00117         else
00118           if (error_code.val == moveit_msgs::MoveItErrorCodes::UNABLE_TO_AQUIRE_SENSOR_DATA)
00119             return "Unable to aquire sensor data";
00120           else
00121             if (error_code.val == moveit_msgs::MoveItErrorCodes::MOTION_PLAN_INVALIDATED_BY_ENVIRONMENT_CHANGE)
00122               return "Motion plan invalidated by environment change";
00123             else
00124               if (error_code.val == moveit_msgs::MoveItErrorCodes::CONTROL_FAILED)
00125                 return "Controller failed during execution";
00126               else
00127                 if (error_code.val == moveit_msgs::MoveItErrorCodes::TIMED_OUT)
00128                   return "Timeout reached";
00129                 else
00130                   if (error_code.val == moveit_msgs::MoveItErrorCodes::PREEMPTED)
00131                     return "Preempted";
00132                   else
00133                     if (error_code.val == moveit_msgs::MoveItErrorCodes::INVALID_GOAL_CONSTRAINTS)
00134                       return "Invalid goal constraints";
00135                     else
00136                       if (error_code.val == moveit_msgs::MoveItErrorCodes::INVALID_GROUP_NAME)
00137                         return "Invalid group name";
00138                       else
00139                         if (error_code.val == moveit_msgs::MoveItErrorCodes::INVALID_OBJECT_NAME)
00140                           return "Invalid object name";
00141                         else
00142                           if (error_code.val == moveit_msgs::MoveItErrorCodes::FAILURE)
00143                             return "Catastrophic failure";
00144   return "Unknown event";
00145 }
00146 
00147 void plan_execution::PlanExecution::planAndExecute(ExecutableMotionPlan &plan, const Options &opt)
00148 {
00149   plan.planning_scene_monitor_ = planning_scene_monitor_;
00150   plan.planning_scene_ = planning_scene_monitor_->getPlanningScene();
00151   planAndExecuteHelper(plan, opt);
00152 }
00153 
00154 void plan_execution::PlanExecution::planAndExecute(ExecutableMotionPlan &plan, const moveit_msgs::PlanningScene &scene_diff, const Options &opt)
00155 {
00156   if (planning_scene::PlanningScene::isEmpty(scene_diff))
00157     planAndExecute(plan, opt);
00158   else
00159   {
00160     plan.planning_scene_monitor_ = planning_scene_monitor_;
00161     {
00162       planning_scene_monitor::LockedPlanningSceneRO lscene(planning_scene_monitor_); // lock the scene so that it does not modify the world representation while diff() is called
00163       plan.planning_scene_ = lscene->diff(scene_diff);
00164     }
00165     planAndExecuteHelper(plan, opt);
00166   }
00167 }
00168 
00169 void plan_execution::PlanExecution::planAndExecuteHelper(ExecutableMotionPlan &plan, const Options &opt)
00170 {
00171   // perform initial configuration steps & various checks
00172   preempt_requested_ = false;
00173 
00174   // run the actual motion plan & execution
00175   unsigned int max_replan_attempts = opt.replan_ ? (opt.replan_attempts_ > 0 ? opt.replan_attempts_ : default_max_replan_attempts_) : 1;
00176   unsigned int replan_attempts = 0;
00177   bool previously_solved = false;
00178 
00179   // run a planning loop for at most the maximum replanning attempts;
00180   // re-planning is executed only in case of known types of failures (e.g., environment changed)
00181   do
00182   {
00183     replan_attempts++;
00184     ROS_INFO("Planning attempt %u of at most %u", replan_attempts, max_replan_attempts);
00185 
00186     if (opt.before_plan_callback_)
00187       opt.before_plan_callback_();
00188 
00189     new_scene_update_ = false; // we clear any scene updates to be evaluated because we are about to compute a new plan, which should consider most recent updates already
00190 
00191     // if we never had a solved plan, or there is no specified way of fixing plans, just call the planner; otherwise, try to repair the plan we previously had;
00192     bool solved = (!previously_solved || !opt.repair_plan_callback_) ?
00193       opt.plan_callback_(plan) :
00194       opt.repair_plan_callback_(plan, trajectory_execution_manager_->getCurrentExpectedTrajectoryIndex());
00195 
00196     if (preempt_requested_)
00197       break;
00198 
00199     // if planning fails in a manner that is not recoverable, we exit the loop,
00200     // otherwise, we attempt to continue, if replanning attempts are left
00201     if (plan.error_code_.val == moveit_msgs::MoveItErrorCodes::PLANNING_FAILED ||
00202     plan.error_code_.val == moveit_msgs::MoveItErrorCodes::INVALID_MOTION_PLAN ||
00203         plan.error_code_.val == moveit_msgs::MoveItErrorCodes::UNABLE_TO_AQUIRE_SENSOR_DATA)
00204     {
00205       if (plan.error_code_.val == moveit_msgs::MoveItErrorCodes::UNABLE_TO_AQUIRE_SENSOR_DATA && opt.replan_delay_ > 0.0)
00206       {
00207     ros::WallDuration d(opt.replan_delay_);
00208     d.sleep();
00209       }
00210       continue;
00211     }
00212 
00213     // abort if no plan was found
00214     if (solved)
00215       previously_solved = true;
00216     else
00217       break;
00218 
00219     if (plan.error_code_.val == moveit_msgs::MoveItErrorCodes::SUCCESS)
00220     {
00221       if (opt.before_execution_callback_)
00222         opt.before_execution_callback_();
00223 
00224       if (preempt_requested_)
00225         break;
00226 
00227       // execute the trajectory, and monitor its executionm
00228       plan.error_code_ = executeAndMonitor(plan);
00229     }
00230 
00231     // if we are done, then we exit the loop
00232     if (plan.error_code_.val == moveit_msgs::MoveItErrorCodes::SUCCESS)
00233       break;
00234 
00235     // if execution failed in a manner that we do not consider recoverable, we exit the loop (with failure)
00236     if (plan.error_code_.val != moveit_msgs::MoveItErrorCodes::MOTION_PLAN_INVALIDATED_BY_ENVIRONMENT_CHANGE)
00237       break;
00238     else
00239     {
00240       // othewrise, we wait (if needed)
00241       if (opt.replan_delay_ > 0.0)
00242       {
00243     ROS_INFO("Waiting for a %lf seconds before attempting a new plan ...", opt.replan_delay_);
00244     ros::WallDuration d(opt.replan_delay_);
00245     d.sleep();
00246     ROS_INFO("Done waiting");
00247       }
00248     }
00249   } while (!preempt_requested_ && max_replan_attempts > replan_attempts);
00250 
00251   if (preempt_requested_)
00252   {
00253     ROS_DEBUG("PlanExecution was preempted");
00254     plan.error_code_.val = moveit_msgs::MoveItErrorCodes::PREEMPTED;
00255   }
00256 
00257   if (opt.done_callback_)
00258     opt.done_callback_();
00259 
00260   if( plan.error_code_.val == moveit_msgs::MoveItErrorCodes::SUCCESS )
00261     ROS_DEBUG("PlanExecution finished successfully.");
00262   else
00263     ROS_DEBUG("PlanExecution terminating with error code %d - '%s'", plan.error_code_.val,
00264               getErrorCodeString(plan.error_code_).c_str());
00265 }
00266 
00267 bool plan_execution::PlanExecution::isRemainingPathValid(const ExecutableMotionPlan &plan)
00268 {
00269   // check the validity of the currently executed path segment only, since there could be
00270   // changes in the world in between path segments
00271   return isRemainingPathValid(plan, trajectory_execution_manager_->getCurrentExpectedTrajectoryIndex());
00272 }
00273 
00274 bool plan_execution::PlanExecution::isRemainingPathValid(const ExecutableMotionPlan &plan, const std::pair<int, int> &path_segment)
00275 {
00276   if (path_segment.first >= 0 && path_segment.second >= 0)
00277   {
00278     planning_scene_monitor::LockedPlanningSceneRO lscene(plan.planning_scene_monitor_); // lock the scene so that it does not modify the world representation while isStateValid() is called
00279     const robot_trajectory::RobotTrajectory &t = *plan.plan_components_[path_segment.first].trajectory_;
00280     const collision_detection::AllowedCollisionMatrix *acm = plan.plan_components_[path_segment.first].allowed_collision_matrix_.get();
00281     std::size_t wpc = t.getWayPointCount();
00282     collision_detection::CollisionRequest req;
00283     req.group_name = t.getGroupName();
00284     for (std::size_t i = std::max(path_segment.second - 1, 0) ; i < wpc ; ++i)
00285     {
00286       collision_detection::CollisionResult res;
00287       if (acm)
00288         plan.planning_scene_->checkCollisionUnpadded(req, res, t.getWayPoint(i), *acm);
00289       else
00290         plan.planning_scene_->checkCollisionUnpadded(req, res, t.getWayPoint(i));
00291 
00292       if (res.collision || !plan.planning_scene_->isStateFeasible(t.getWayPoint(i), false))
00293       {
00294         // Dave's debacle
00295         ROS_INFO("Trajectory component '%s' is invalid", plan.plan_components_[path_segment.first].description_.c_str());
00296 
00297         // call the same functions again, in verbose mode, to show what issues have been detected
00298         plan.planning_scene_->isStateFeasible(t.getWayPoint(i), true);
00299         req.verbose = true;
00300         res.clear();
00301         if (acm)
00302           plan.planning_scene_->checkCollisionUnpadded(req, res, t.getWayPoint(i), *acm);
00303         else
00304           plan.planning_scene_->checkCollisionUnpadded(req, res, t.getWayPoint(i));
00305         return false;
00306       }
00307     }
00308   }
00309   return true;
00310 }
00311 
00312 moveit_msgs::MoveItErrorCodes plan_execution::PlanExecution::executeAndMonitor(const ExecutableMotionPlan &plan)
00313 {
00314   moveit_msgs::MoveItErrorCodes result;
00315 
00316   // try to execute the trajectory
00317   execution_complete_ = true;
00318 
00319   if (!trajectory_execution_manager_)
00320   {
00321     ROS_ERROR("No trajectory execution manager");
00322     result.val = moveit_msgs::MoveItErrorCodes::CONTROL_FAILED;
00323     return result;
00324   }
00325 
00326   if (plan.plan_components_.empty())
00327   {
00328     result.val = moveit_msgs::MoveItErrorCodes::SUCCESS;
00329     return result;
00330   }
00331 
00332   execution_complete_ = false;
00333 
00334   // push the trajectories we have slated for execution to the trajectory execution manager
00335   int prev = -1;
00336   for (std::size_t i = 0 ; i < plan.plan_components_.size() ; ++i)
00337   {
00338     if (!plan.plan_components_[i].trajectory_ || plan.plan_components_[i].trajectory_->empty())
00339       continue;
00340 
00341     // \todo should this be in trajectory_execution ? Maybe. Then that will have to use kinematic_trajectory too;
00342     // spliting trajectories for controllers becomes interesting: tied to groups instead of joints. this could cause some problems
00343     // in the meantime we do a hack:
00344 
00345     bool unwound = false;
00346     for (std::size_t j = 0 ; j < i ; ++j)
00347       // if we ran unwind on a path for the same group
00348       if (plan.plan_components_[j].trajectory_ && plan.plan_components_[j].trajectory_->getGroup() == plan.plan_components_[i].trajectory_->getGroup() && !plan.plan_components_[j].trajectory_->empty())
00349       {
00350         plan.plan_components_[i].trajectory_->unwind(plan.plan_components_[j].trajectory_->getLastWayPoint());
00351         unwound = true;
00352         break;
00353       }
00354 
00355     if (!unwound)
00356     {
00357       // unwind the path to execute based on the current state of the system
00358       if (prev < 0)
00359         plan.plan_components_[i].trajectory_->unwind(plan.planning_scene_monitor_ && plan.planning_scene_monitor_->getStateMonitor() ?
00360                                                      *plan.planning_scene_monitor_->getStateMonitor()->getCurrentState() :
00361                                                      plan.planning_scene_->getCurrentState());
00362       else
00363         plan.plan_components_[i].trajectory_->unwind(plan.plan_components_[prev].trajectory_->getLastWayPoint());
00364     }
00365 
00366     prev = i;
00367 
00368     // convert to message, pass along
00369     moveit_msgs::RobotTrajectory msg;
00370     plan.plan_components_[i].trajectory_->getRobotTrajectoryMsg(msg);
00371     if (!trajectory_execution_manager_->push(msg))
00372     {
00373       trajectory_execution_manager_->clear();
00374       ROS_ERROR_STREAM("Apparently trajectory initialization failed");
00375       execution_complete_ = true;
00376       result.val = moveit_msgs::MoveItErrorCodes::CONTROL_FAILED;
00377       return result;
00378     }
00379   }
00380 
00381   if (!trajectory_monitor_ && planning_scene_monitor_->getStateMonitor())
00382     trajectory_monitor_.reset(new planning_scene_monitor::TrajectoryMonitor(planning_scene_monitor_->getStateMonitor()));
00383 
00384   // start recording trajectory states
00385   if (trajectory_monitor_)
00386     trajectory_monitor_->startTrajectoryMonitor();
00387 
00388   // start a trajectory execution thread
00389   trajectory_execution_manager_->execute(boost::bind(&PlanExecution::doneWithTrajectoryExecution, this, _1),
00390                                          boost::bind(&PlanExecution::successfulTrajectorySegmentExecution, this, &plan, _1));
00391   // wait for path to be done, while checking that the path does not become invalid
00392   ros::Rate r(100);
00393   path_became_invalid_ = false;
00394   while (node_handle_.ok() && !execution_complete_ && !preempt_requested_ && !path_became_invalid_)
00395   {
00396     r.sleep();
00397     // check the path if there was an environment update in the meantime
00398     if (new_scene_update_)
00399     {
00400       new_scene_update_ = false;
00401       if (!isRemainingPathValid(plan))
00402       {
00403         path_became_invalid_ = true;
00404         break;
00405       }
00406     }
00407   }
00408 
00409   // stop execution if needed
00410   if (preempt_requested_)
00411   {
00412     ROS_INFO("Stopping execution due to preempt request");
00413     trajectory_execution_manager_->stopExecution();
00414   }
00415   else
00416     if (path_became_invalid_)
00417     {
00418       ROS_INFO("Stopping execution because the path to execute became invalid (probably the environment changed)");
00419       trajectory_execution_manager_->stopExecution();
00420     }
00421     else
00422       if (!execution_complete_)
00423       {
00424         ROS_WARN("Stopping execution due to unknown reason. Possibly the node is about to shut down.");
00425         trajectory_execution_manager_->stopExecution();
00426       }
00427 
00428   // stop recording trajectory states
00429   if (trajectory_monitor_)
00430     trajectory_monitor_->stopTrajectoryMonitor();
00431 
00432   // decide return value
00433   if (path_became_invalid_)
00434     result.val = moveit_msgs::MoveItErrorCodes::MOTION_PLAN_INVALIDATED_BY_ENVIRONMENT_CHANGE;
00435   else
00436   {
00437     if (preempt_requested_)
00438     {
00439       result.val = moveit_msgs::MoveItErrorCodes::PREEMPTED;
00440     }
00441     else
00442     {
00443       if (trajectory_execution_manager_->getLastExecutionStatus() == moveit_controller_manager::ExecutionStatus::SUCCEEDED)
00444     result.val = moveit_msgs::MoveItErrorCodes::SUCCESS;
00445       else
00446         if (trajectory_execution_manager_->getLastExecutionStatus() == moveit_controller_manager::ExecutionStatus::TIMED_OUT)
00447       result.val = moveit_msgs::MoveItErrorCodes::TIMED_OUT;
00448     else
00449       result.val = moveit_msgs::MoveItErrorCodes::CONTROL_FAILED;
00450     }
00451   }
00452   return result;
00453 }
00454 
00455 void plan_execution::PlanExecution::planningSceneUpdatedCallback(const planning_scene_monitor::PlanningSceneMonitor::SceneUpdateType update_type)
00456 {
00457   if (update_type & (planning_scene_monitor::PlanningSceneMonitor::UPDATE_GEOMETRY | planning_scene_monitor::PlanningSceneMonitor::UPDATE_TRANSFORMS))
00458     new_scene_update_ = true;
00459 }
00460 
00461 void plan_execution::PlanExecution::doneWithTrajectoryExecution(const moveit_controller_manager::ExecutionStatus &status)
00462 {
00463   execution_complete_ = true;
00464 }
00465 
00466 void plan_execution::PlanExecution::successfulTrajectorySegmentExecution(const ExecutableMotionPlan *plan, std::size_t index)
00467 {
00468   ROS_DEBUG("Completed '%s'", plan->plan_components_[index].description_.c_str());
00469 
00470   // if any side-effects are associated to the trajectory part that just completed, execute them
00471   if (plan->plan_components_[index].effect_on_success_)
00472     if (!plan->plan_components_[index].effect_on_success_(plan))
00473     {
00474       // execution of side-effect failed
00475       ROS_ERROR("Execution of path-completion side-effect failed. Preempting.");
00476       preempt_requested_ = true;
00477       return;
00478     }
00479 
00480   // if there is a next trajectory, check it for validity, before we start execution
00481   std::size_t test_index = index;
00482   while (++test_index < plan->plan_components_.size())
00483     if (plan->plan_components_[test_index].trajectory_ && !plan->plan_components_[test_index].trajectory_->empty())
00484     {
00485       if (!isRemainingPathValid(*plan, std::make_pair<int>(test_index, 0)))
00486         path_became_invalid_ = true;
00487       break;
00488     }
00489 }


planning
Author(s): Ioan Sucan , Sachin Chitta
autogenerated on Mon Oct 6 2014 02:31:39