object_manipulator.cpp
Go to the documentation of this file.
00001 /*********************************************************************
00002 *
00003 *  Copyright (c) 2009, Willow Garage, Inc.
00004 *  All rights reserved.
00005 *
00006 *  Redistribution and use in source and binary forms, with or without
00007 *  modification, are permitted provided that the following conditions
00008 *  are met:
00009 *
00010 *   * Redistributions of source code must retain the above copyright
00011 *     notice, this list of conditions and the following disclaimer.
00012 *   * Redistributions in binary form must reproduce the above
00013 *     copyright notice, this list of conditions and the following
00014 *     disclaimer in the documentation and/or other materials provided
00015 *     with the distribution.
00016 *   * Neither the name of the Willow Garage nor the names of its
00017 *     contributors may be used to endorse or promote products derived
00018 *     from this software without specific prior written permission.
00019 *
00020 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00021 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00022 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00023 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00024 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00025 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00026 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00027 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00028 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00029 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00030 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00031 *  POSSIBILITY OF SUCH DAMAGE.
00032 *********************************************************************/
00033 
00034 // Author(s): Matei Ciocarlie
00035 
00036 #include "object_manipulator/object_manipulator.h"
00037 
00038 #include <algorithm>
00039 
00040 //#define PROF_ENABLED
00041 //#include <profiling/profiling.h>
00042 //PROF_DECLARE(TOTAL_PICKUP_TIMER);
00043 
00044 //#include <demo_synchronizer/synchronizer_client.h>
00045 
00046 #include <object_manipulation_msgs/tools.h>
00047 
00048 //old style executors
00049 #include "object_manipulator/grasp_execution/grasp_executor_with_approach.h"
00050 #include "object_manipulator/grasp_execution/reactive_grasp_executor.h"
00051 #include "object_manipulator/grasp_execution/unsafe_grasp_executor.h"
00052 #include "object_manipulator/place_execution/place_executor.h"
00053 
00054 //new style executors
00055 #include "object_manipulator/grasp_execution/approach_lift_grasp.h"
00056 #include "object_manipulator/grasp_execution/grasp_tester_fast.h"
00057 #include "object_manipulator/place_execution/descend_retreat_place.h"
00058 #include "object_manipulator/place_execution/place_tester_fast.h"
00059 
00060 #include "object_manipulator/tools/grasp_marker_publisher.h"
00061 #include "object_manipulator/tools/exceptions.h"
00062 
00063 using object_manipulation_msgs::GraspableObject;
00064 using object_manipulation_msgs::PickupGoal;
00065 using object_manipulation_msgs::PickupResult;
00066 using object_manipulation_msgs::PickupFeedback;
00067 using object_manipulation_msgs::PlaceGoal;
00068 using object_manipulation_msgs::PlaceResult;
00069 using object_manipulation_msgs::PlaceFeedback;
00070 using object_manipulation_msgs::ManipulationResult;
00071 using object_manipulation_msgs::GraspResult;
00072 using object_manipulation_msgs::PlaceLocationResult;
00073 using object_manipulation_msgs::getGraspResultInfo;
00074 using object_manipulation_msgs::getPlaceLocationResultInfo;
00075 using object_manipulation_msgs::Grasp;
00076 using object_manipulation_msgs::GraspPlanningAction;
00077 
00078 namespace object_manipulator {
00079 
00080 ObjectManipulator::ObjectManipulator() :
00081   priv_nh_("~"),
00082   root_nh_(""),
00083   grasp_planning_actions_("", "", false, false),
00084   marker_pub_(NULL)
00085 {
00086   bool publish_markers = true;
00087   if (publish_markers)
00088   {
00089     marker_pub_ = new GraspMarkerPublisher();
00090   }
00091 
00092   //old style executors
00093   grasp_executor_with_approach_ = new GraspExecutorWithApproach(marker_pub_);
00094   reactive_grasp_executor_ = new ReactiveGraspExecutor(marker_pub_);
00095   unsafe_grasp_executor_ = new UnsafeGraspExecutor(marker_pub_);
00096   place_executor_ = new PlaceExecutor(marker_pub_);
00097   reactive_place_executor_ = new ReactivePlaceExecutor(marker_pub_);
00098 
00099   //new syle executors
00100 
00101   priv_nh_.param<std::string>("kinematics_plugin_name", kinematics_plugin_name_, "pr2_arm_kinematics/PR2ArmKinematicsPlugin");
00102   
00103   grasp_tester_with_approach_ = new GraspTesterWithApproach;
00104   grasp_tester_with_approach_->setMarkerPublisher(marker_pub_);
00105   grasp_tester_fast_ = new GraspTesterFast(NULL, kinematics_plugin_name_);
00106   grasp_tester_fast_->setMarkerPublisher(marker_pub_);
00107   unsafe_grasp_tester_ = new UnsafeGraspTester;
00108   unsafe_grasp_tester_->setMarkerPublisher(marker_pub_);
00109   standard_grasp_performer_ = new StandardGraspPerformer;
00110   standard_grasp_performer_->setMarkerPublisher(marker_pub_);
00111   reactive_grasp_performer_ = new ReactiveGraspPerformer;
00112   reactive_grasp_performer_->setMarkerPublisher(marker_pub_);
00113   unsafe_grasp_performer_ = new UnsafeGraspPerformer;
00114   unsafe_grasp_performer_->setMarkerPublisher(marker_pub_);
00115  
00116   standard_place_tester_ = new PlaceTesterFast(NULL, kinematics_plugin_name_);
00117   standard_place_tester_->setMarkerPublisher(marker_pub_);
00118   standard_place_performer_ = new StandardPlacePerformer;
00119   standard_place_performer_->setMarkerPublisher(marker_pub_);
00120   reactive_place_performer_ = new ReactivePlacePerformer;
00121   reactive_place_performer_->setMarkerPublisher(marker_pub_);
00122 
00123   priv_nh_.param<std::string>("default_cluster_planner", default_cluster_planner_, "default_cluster_planner");
00124   priv_nh_.param<std::string>("default_database_planner", default_database_planner_, "default_database_planner");
00125   priv_nh_.param<std::string>("default_probabilistic_planner", default_probabilistic_planner_,
00126     "default_probabilistic_planner");
00127   priv_nh_.param<bool>("use_probabilistic_grasp_planner", use_probabilistic_planner_, false);
00128   priv_nh_.param<bool>("randomize_grasps", randomize_grasps_, false);
00129 
00130   ROS_INFO("Object manipulator ready. Default cluster planner: %s. Default database planner: %s.", 
00131            default_cluster_planner_.c_str(), default_database_planner_.c_str());
00132   if(use_probabilistic_planner_)
00133   {
00134     ROS_INFO("Probabilistic planner enabled");
00135   }
00136   ROS_INFO_NAMED("manipulation","Object manipulator ready");
00137 }
00138 
00139 ObjectManipulator::~ObjectManipulator()
00140 {
00141   delete marker_pub_;
00142 
00143   //old style executors
00144   delete grasp_executor_with_approach_;
00145   delete reactive_grasp_executor_;
00146   delete unsafe_grasp_executor_;
00147   delete place_executor_;
00148   delete reactive_place_executor_;
00149 
00150   //new style executors
00151   delete grasp_tester_fast_;
00152   delete grasp_tester_with_approach_;
00153   delete unsafe_grasp_tester_;
00154   delete standard_grasp_performer_;
00155   delete reactive_grasp_performer_;
00156   delete unsafe_grasp_performer_;
00157 
00158   delete standard_place_tester_;
00159   delete standard_place_performer_;
00160   delete reactive_place_performer_;
00161 }
00162 
00163 void ObjectManipulator::graspFeedback(
00164                                  actionlib::SimpleActionServer<object_manipulation_msgs::PickupAction> *action_server,
00165                                  size_t tested_grasps, size_t current_grasp)
00166 {
00167   PickupFeedback feedback;
00168   feedback.total_grasps = grasp_container_.size();
00169   feedback.current_grasp = current_grasp + tested_grasps;
00170   action_server->publishFeedback(feedback);
00171 }
00172 
00173 void ObjectManipulator::graspPlanningFeedbackCallback(
00174                                              const object_manipulation_msgs::GraspPlanningFeedbackConstPtr &feedback)
00175 {
00176   ROS_DEBUG_STREAM_NAMED("manipulation", "Feedback from planning action, total grasps: " << feedback->grasps.size());
00177   grasp_container_.addGrasps(feedback->grasps);
00178 }
00179 
00180 void ObjectManipulator::graspPlanningDoneCallback(const actionlib::SimpleClientGoalState& state,
00181                                              const object_manipulation_msgs::GraspPlanningResultConstPtr &result)
00182 {
00183   if (state == actionlib::SimpleClientGoalState::SUCCEEDED)
00184   {
00185     ROS_DEBUG_STREAM_NAMED("manipulation", "Final result from planning action, total grasps: " << result->grasps.size());
00186     grasp_container_.addGrasps(result->grasps);
00187   }
00188   else
00189   {
00190     ROS_ERROR("Grasp planning action did not succeed");
00191   }
00192 }
00193 
00194 void ObjectManipulator::pickup(const PickupGoal::ConstPtr &pickup_goal,
00195                                actionlib::SimpleActionServer<object_manipulation_msgs::PickupAction> *action_server)
00196 {
00197   //the result that will be returned
00198   PickupResult result;
00199 
00200   //we are making some assumptions here. We are assuming that the frame of the cluster is the
00201   //cannonical frame of the system, so here we check that the frames of all recognitions
00202   //agree with that. 
00203   //TODO find a general solution for this problem
00204   if ( pickup_goal->target.cluster.points.size() > 0)
00205   {
00206     for (size_t i=0; i<pickup_goal->target.potential_models.size(); i++)
00207     {
00208       if ( pickup_goal->target.potential_models[i].pose.header.frame_id != pickup_goal->target.cluster.header.frame_id)
00209       {
00210         ROS_ERROR("Target object recognition result(s) not in the same frame as the cluster");
00211         result.manipulation_result.value = ManipulationResult::ERROR;
00212         action_server->setAborted(result);
00213         return;
00214       }
00215     }
00216   }
00217   
00218   //populate the grasp container
00219   grasp_container_.clear();
00220   bool using_planner_action;
00221   std::string planner_action;
00222   if (!pickup_goal->desired_grasps.empty())
00223   {
00224     //use the requested grasps, if any
00225     grasp_container_.addGrasps(pickup_goal->desired_grasps);
00226     using_planner_action = false;
00227   }
00228   else
00229   {
00230     if (use_probabilistic_planner_)
00231     {
00232         ROS_INFO("Using probabilistic planner");
00233         // use the default probabilistic planner
00234         planner_action = default_probabilistic_planner_;
00235     }
00236     else
00237     {
00238         // decide which grasp planner to call depending on the type of object
00239         if (!pickup_goal->target.potential_models.empty())
00240             planner_action = default_database_planner_;
00241         else
00242             planner_action = default_cluster_planner_;        
00243     }
00244 
00245     //call the planner action, which will populate the grasp container as feedback arrives
00246     object_manipulation_msgs::GraspPlanningGoal goal;
00247     goal.arm_name = pickup_goal->arm_name;
00248     goal.target = pickup_goal->target;
00249     goal.collision_object_name = pickup_goal->collision_object_name;
00250     goal.collision_support_surface_name = pickup_goal->collision_support_surface_name;
00251     goal.movable_obstacles = pickup_goal->movable_obstacles;
00252     try
00253     {
00254       grasp_planning_actions_.client(planner_action).sendGoal(goal, 
00255                                           boost::bind(&ObjectManipulator::graspPlanningDoneCallback, this, _1, _2),
00256                                           actionlib::SimpleActionClient<GraspPlanningAction>::SimpleActiveCallback(), 
00257                                           boost::bind(&ObjectManipulator::graspPlanningFeedbackCallback, this, _1));
00258     }
00259     catch (ServiceNotFoundException &ex)
00260     {
00261       ROS_ERROR("Planning action %s not found", planner_action.c_str());
00262       result.manipulation_result.value = ManipulationResult::ERROR;
00263       action_server->setAborted(result);
00264       return;
00265     }
00266     using_planner_action = true;
00267   }
00268   ScopedGoalCancel<GraspPlanningAction> goal_cancel(NULL);
00269   if (using_planner_action)
00270   {
00271     goal_cancel.setClient(&grasp_planning_actions_.client(planner_action));
00272   }
00273   //decide which grasp tester and performer will be used
00274   GraspTester *grasp_tester;
00275   GraspPerformer *grasp_performer;
00276   if (pickup_goal->ignore_collisions) 
00277   {
00278     grasp_tester = unsafe_grasp_tester_;
00279     grasp_performer = unsafe_grasp_performer_;
00280   }
00281   else 
00282   {
00283     grasp_tester = grasp_tester_fast_;
00284     if (pickup_goal->use_reactive_execution)
00285     {
00286       grasp_performer = reactive_grasp_performer_;
00287     }
00288     else
00289     {
00290       grasp_performer = standard_grasp_performer_;
00291     }
00292   }
00293 
00294   grasp_tester->setInterruptFunction(
00295                boost::bind(&actionlib::SimpleActionServer<object_manipulation_msgs::PickupAction>::isPreemptRequested,
00296                            action_server));
00297   grasp_performer->setInterruptFunction(
00298                boost::bind(&actionlib::SimpleActionServer<object_manipulation_msgs::PickupAction>::isPreemptRequested,
00299                            action_server));
00300 
00301   //PROF_RESET_ALL;
00302   //PROF_START_TIMER(TOTAL_PICKUP_TIMER);
00303 
00304   ros::WallDuration dur(1.0);
00305   dur.sleep();
00306 
00307   arm_navigation_msgs::OrderedCollisionOperations emp_coll;
00308   std::vector<arm_navigation_msgs::LinkPadding> link_padding;
00309   mechInterface().getPlanningScene(emp_coll, link_padding);
00310 
00311   std::map<unsigned int, unsigned int> results;
00312 
00313   ros::WallTime start = ros::WallTime::now();
00314 
00315   //try the grasps in the list until one succeeds
00316   result.manipulation_result.value = ManipulationResult::UNFEASIBLE;
00317   try
00318   {
00319     size_t tested_grasps = 0;
00320     while (1)
00321     {
00322       if (action_server->isPreemptRequested()) throw InterruptRequestedException();
00323 
00324       ROS_DEBUG_STREAM_NAMED("manipulation", "Object manipulator: getting grasps beyond " << tested_grasps);
00325       std::vector<object_manipulation_msgs::Grasp> new_grasps = grasp_container_.getGrasps(tested_grasps);
00326       if ( new_grasps.empty() )
00327       { 
00328         if ( using_planner_action && (grasp_planning_actions_.client(planner_action).getState() == 
00329                                       actionlib::SimpleClientGoalState::ACTIVE || 
00330                                       grasp_planning_actions_.client(planner_action).getState() == 
00331                                       actionlib::SimpleClientGoalState::PENDING) )
00332         {
00333           ROS_DEBUG_NAMED("manipulation", "Object manipulator: waiting for planner action to provide grasps");
00334           ros::Duration(0.25).sleep();
00335           continue;
00336         }
00337         else
00338         {
00339           ROS_INFO("Object manipulator: all grasps have been tested");
00340           break;
00341         }
00342       }
00343       grasp_tester->setFeedbackFunction(boost::bind(&ObjectManipulator::graspFeedback, 
00344                                                     this, action_server, tested_grasps,  _1));
00345       //test a batch of grasps
00346       std::vector<GraspExecutionInfo> execution_info;
00347       grasp_tester->testGrasps(*pickup_goal, new_grasps, execution_info, !pickup_goal->only_perform_feasibility_test);
00348       if (execution_info.empty()) throw GraspException("grasp tester provided empty ExecutionInfo");
00349       if (execution_info.empty()) throw GraspException("grasp tester provided empty ExecutionInfo");
00350       //try to perform them
00351       if (!pickup_goal->only_perform_feasibility_test)
00352       {
00353         ROS_DEBUG_NAMED("manipulation", "Attempting to perform grasps");
00354         grasp_performer->performGrasps(*pickup_goal, new_grasps, execution_info);
00355       }
00356       if (execution_info.empty()) throw GraspException("grasp performer provided empty ExecutionInfo");
00357       //copy information about tested grasps over in result
00358       for (size_t i=0; i<execution_info.size(); i++)
00359       {
00360         result.attempted_grasps.push_back(new_grasps[i]);
00361         result.attempted_grasp_results.push_back(execution_info[i].result_);
00362       }
00363       //see if we're done
00364       if (execution_info.back().result_.result_code == GraspResult::SUCCESS)
00365       {
00366         result.manipulation_result.value = ManipulationResult::SUCCESS;
00367         if (!pickup_goal->only_perform_feasibility_test)
00368         {
00369           ROS_DEBUG_NAMED("manipulation", "Grasp reports success");
00370           result.grasp = new_grasps.at( execution_info.size() -1 );
00371           action_server->setSucceeded(result);
00372           return;
00373         }
00374       }
00375       //see if continuation is possible
00376       if (!execution_info.back().result_.continuation_possible)
00377       {
00378         if (pickup_goal->only_perform_feasibility_test)
00379         {
00380           ROS_ERROR("Continuation impossible when performing feasibility test");
00381         }
00382         result.grasp = new_grasps.at( execution_info.size() -1 );
00383         if (execution_info.back().result_.result_code == GraspResult::LIFT_FAILED)
00384           result.manipulation_result.value = ManipulationResult::LIFT_FAILED;
00385         else
00386           result.manipulation_result.value = ManipulationResult::FAILED;
00387         action_server->setAborted(result);
00388         return;
00389       }
00390       //remember how many grasps we've tried
00391       tested_grasps += execution_info.size();
00392     }
00393     //all the grasps have been tested
00394     if (pickup_goal->only_perform_feasibility_test && result.manipulation_result.value == ManipulationResult::SUCCESS)
00395     {
00396       action_server->setSucceeded(result);
00397     }
00398     else
00399     {
00400       action_server->setAborted(result);
00401     }
00402     return;
00403   }
00404   catch (InterruptRequestedException &ex)
00405   {
00406     ROS_DEBUG_NAMED("manipulation","Pickup goal preempted");
00407     action_server->setPreempted();
00408     return;
00409   }
00410   catch (MoveArmStuckException &ex)
00411   {
00412     ROS_ERROR("Grasp aborted because move_arm is stuck");
00413     result.manipulation_result.value = ManipulationResult::ARM_MOVEMENT_PREVENTED;
00414     action_server->setAborted(result);
00415     return;
00416   }
00417   catch (GraspException &ex)
00418   {
00419     ROS_ERROR("Grasp error; exception: %s", ex.what());
00420     result.manipulation_result.value = ManipulationResult::ERROR;
00421     action_server->setAborted(result);
00422     return;
00423   }
00424 }
00425 
00426 void ObjectManipulator::placeFeedback(
00427                                  actionlib::SimpleActionServer<object_manipulation_msgs::PlaceAction> *action_server,
00428                                  size_t tested_places, size_t total_places, size_t current_place)
00429 {
00430   PlaceFeedback feedback;
00431   feedback.total_locations = total_places;
00432   feedback.current_location = current_place + tested_places;
00433   action_server->publishFeedback(feedback);
00434 }
00435 
00436 void ObjectManipulator::place(const object_manipulation_msgs::PlaceGoal::ConstPtr &place_goal,
00437                               actionlib::SimpleActionServer<object_manipulation_msgs::PlaceAction> *action_server)
00438 {
00439   PlaceResult result;
00440   PlaceTester *place_tester = standard_place_tester_;
00441   PlacePerformer *place_performer = standard_place_performer_;
00442   if (place_goal->use_reactive_place) place_performer = reactive_place_performer_;
00443   
00444   place_tester->setInterruptFunction(
00445                boost::bind(&actionlib::SimpleActionServer<object_manipulation_msgs::PlaceAction>::isPreemptRequested,
00446                            action_server));
00447   place_performer->setInterruptFunction(
00448                boost::bind(&actionlib::SimpleActionServer<object_manipulation_msgs::PlaceAction>::isPreemptRequested,
00449                            action_server));
00450 
00451   std::vector<geometry_msgs::PoseStamped> place_locations = place_goal->place_locations;
00452   try
00453   {
00454     std::vector<PlaceExecutionInfo> execution_info;
00455     result.manipulation_result.value = ManipulationResult::UNFEASIBLE;
00456     size_t tested_places = 0;
00457     while (!place_locations.empty())
00458     {
00459       if (action_server->isPreemptRequested()) throw InterruptRequestedException();
00460       place_tester->setFeedbackFunction(boost::bind(&ObjectManipulator::placeFeedback, 
00461                                                     this, action_server, tested_places, place_locations.size(), _1));
00462       //test a batch of locations
00463       place_tester->testPlaces(*place_goal, place_locations, execution_info, 
00464                                !place_goal->only_perform_feasibility_test);
00465       if (execution_info.empty()) throw GraspException("place tester provided empty ExecutionInfo");
00466       //try to perform them
00467       if (!place_goal->only_perform_feasibility_test)
00468       {
00469         place_performer->performPlaces(*place_goal, place_locations, execution_info);
00470       }
00471       if (execution_info.empty()) throw GraspException("place performer provided empty ExecutionInfo");
00472       //copy information about tested places over in result
00473       std::vector<geometry_msgs::PoseStamped>::iterator it = place_locations.begin();
00474       for (size_t i=0; i<execution_info.size(); i++)
00475       {
00476         result.attempted_locations.push_back(place_locations[i]);
00477         result.attempted_location_results.push_back(execution_info[i].result_);
00478         it++;
00479       }
00480       //see if we're done
00481       if (execution_info.back().result_.result_code == PlaceLocationResult::SUCCESS)
00482       {
00483         result.manipulation_result.value = ManipulationResult::SUCCESS;
00484         if (!place_goal->only_perform_feasibility_test)
00485         {
00486           result.place_location = place_locations.at( execution_info.size() - 1 );
00487           action_server->setSucceeded(result);
00488           return;
00489         }
00490       }
00491       //see if continuation is possible
00492       if (!execution_info.back().result_.continuation_possible)
00493       {
00494         if (place_goal->only_perform_feasibility_test)
00495         {
00496           ROS_ERROR("Continuation impossible when performing feasibility test");
00497         }
00498         result.place_location = place_locations.at( execution_info.size() - 1 );
00499         if (execution_info.back().result_.result_code == PlaceLocationResult::RETREAT_FAILED)
00500           result.manipulation_result.value = ManipulationResult::RETREAT_FAILED;
00501         else
00502           result.manipulation_result.value = ManipulationResult::FAILED;
00503         action_server->setAborted(result);
00504         return;
00505       }
00506       //clear all the grasps we've tried
00507       tested_places += execution_info.size();
00508       execution_info.clear();      
00509       place_locations.erase(place_locations.begin(), it);
00510     }
00511     //all the grasps have been tested
00512     if (place_goal->only_perform_feasibility_test && result.manipulation_result.value == ManipulationResult::SUCCESS)
00513     {
00514       action_server->setSucceeded(result);
00515     }
00516     else
00517     {
00518       action_server->setAborted(result);
00519     }
00520     return;
00521   }
00522   catch (InterruptRequestedException &ex)
00523   {
00524     ROS_DEBUG_NAMED("manipulation","Place goal preempted");
00525     action_server->setPreempted();
00526     return;
00527   }
00528   catch (MoveArmStuckException &ex)
00529   {
00530     ROS_ERROR("Place aborted because move_arm is stuck");
00531     result.manipulation_result.value = ManipulationResult::ARM_MOVEMENT_PREVENTED;
00532     action_server->setAborted(result);
00533     return;
00534   }
00535   catch (GraspException &ex)
00536   {
00537     ROS_ERROR("Place error; exception: %s", ex.what());
00538     result.manipulation_result.value = ManipulationResult::ERROR;
00539     action_server->setAborted(result);
00540     return;
00541   } 
00542 }
00543 
00544 }
00545 


object_manipulator
Author(s): Matei Ciocarlie and Kaijen Hsiao
autogenerated on Thu Jan 2 2014 11:39:04