simple_pick_and_place_test.cpp
Go to the documentation of this file.
00001 #include <ros/ros.h>
00002 
00003 #include <tf/transform_listener.h>
00004 #include <actionlib/client/simple_action_client.h>
00005 #include <tabletop_object_detector/TabletopDetection.h>
00006 #include <tabletop_collision_map_processing/TabletopCollisionMapProcessing.h>
00007 #include <object_manipulation_msgs/PickupAction.h>
00008 #include <object_manipulation_msgs/PlaceAction.h>
00009 #include <object_manipulation_msgs/ManipulationResult.h>
00010 #include <arm_navigation_msgs/MoveArmAction.h>
00011 #include <std_srvs/Empty.h>
00012 
00013 static const double TABLE_HEIGHT = 0.28;
00014 
00015 tf::TransformListener *tf_listener;
00016 
00017 
00018 static const size_t NUM_JOINTS = 5;
00019 
00020 bool move_to_joint_goal(std::vector<arm_navigation_msgs::JointConstraint> joint_constraints,
00021     actionlib::SimpleActionClient<arm_navigation_msgs::MoveArmAction> &move_arm) {
00022 
00023   arm_navigation_msgs::MoveArmGoal goal;
00024 
00025   goal.motion_plan_request.group_name = "arm";
00026   goal.motion_plan_request.num_planning_attempts = 1;
00027   goal.motion_plan_request.allowed_planning_time = ros::Duration(5.0);
00028 
00029   goal.motion_plan_request.planner_id = std::string("");
00030   goal.planner_service_name = std::string("ompl_planning/plan_kinematic_path");
00031 
00032   goal.motion_plan_request.goal_constraints.joint_constraints = joint_constraints;
00033 
00034 
00035   bool finished_within_time = false;
00036   move_arm.sendGoal(goal);
00037   finished_within_time = move_arm.waitForResult(ros::Duration(40.0));
00038   if (!finished_within_time)
00039   {
00040     move_arm.cancelGoal();
00041     ROS_INFO("Timed out achieving goal!");
00042     return false;
00043   }
00044   else
00045   {
00046     actionlib::SimpleClientGoalState state = move_arm.getState();
00047     bool success = (state == actionlib::SimpleClientGoalState::SUCCEEDED);
00048     if (success)
00049       ROS_INFO("Action finished: %s",state.toString().c_str());
00050     else
00051       ROS_INFO("Action failed: %s",state.toString().c_str());
00052 
00053     return success;
00054   }
00055 }
00056 
00057 
00061 bool nearest_object(std::vector<object_manipulation_msgs::GraspableObject>& objects, geometry_msgs::PointStamped& reference_point, int& object_ind)
00062 {
00063   geometry_msgs::PointStamped point;
00064 
00065   // convert point to base_link frame
00066   tf_listener->transformPoint("/base_link", reference_point, point);
00067 
00068   // find the closest object
00069   double nearest_dist = 1e6;
00070   int nearest_object_ind = -1;
00071 
00072   for (size_t i = 0; i < objects.size(); ++i)
00073   {
00074     sensor_msgs::PointCloud cloud;
00075     tf_listener->transformPointCloud("/base_link", objects[i].cluster, cloud);
00076 
00077     // calculate average
00078     float x = 0.0, y = 0.0, z = 0.0;
00079     for (size_t j = 0; j < cloud.points.size(); ++j)
00080     {
00081       x += cloud.points[j].x;
00082       y += cloud.points[j].y;
00083       z += cloud.points[j].z;
00084     }
00085     x /= cloud.points.size();
00086     y /= cloud.points.size();
00087     z /= cloud.points.size();
00088 
00089     double dist = sqrt(pow(x - point.point.x, 2.0) + pow(y - point.point.y, 2.0) + pow(z - point.point.z, 2.0));
00090     if (dist < nearest_dist)
00091     {
00092       nearest_dist = dist;
00093       nearest_object_ind = i;
00094     }
00095   }
00096 
00097   if (nearest_object_ind > -1)
00098   {
00099     ROS_INFO("nearest object ind: %d (distance: %f)", nearest_object_ind, nearest_dist);
00100     object_ind = nearest_object_ind;
00101     return true;
00102   } else
00103   {
00104     ROS_ERROR("No nearby objects. Unable to select grasp target");
00105     return false;
00106   }
00107 }
00108 
00109 int main(int argc, char **argv)
00110 {
00111   //initialize the ROS node
00112   ros::init(argc, argv, "pick_and_place_app");
00113   ros::NodeHandle nh;
00114 
00115   //set service and action names
00116   const std::string OBJECT_DETECTION_SERVICE_NAME = "/object_detection";
00117   const std::string COLLISION_PROCESSING_SERVICE_NAME = "/tabletop_collision_map_processing/tabletop_collision_map_processing";
00118   const std::string PICKUP_ACTION_NAME = "/object_manipulator/object_manipulator_pickup";
00119   const std::string PLACE_ACTION_NAME = "/object_manipulator/object_manipulator_place";
00120   const std::string MOVE_ARM_ACTION_NAME = "/move_arm";
00121   const std::string COLLIDER_RESET_SERVICE_NAME = "/collider_node/reset";
00122 
00123   // create TF listener
00124   tf_listener = new tf::TransformListener();
00125 
00126   //create service and action clients
00127   ros::ServiceClient object_detection_srv;
00128   ros::ServiceClient collision_processing_srv;
00129   ros::ServiceClient collider_reset_srv;
00130   actionlib::SimpleActionClient<object_manipulation_msgs::PickupAction>
00131     pickup_client(PICKUP_ACTION_NAME, true);
00132   actionlib::SimpleActionClient<object_manipulation_msgs::PlaceAction>
00133     place_client(PLACE_ACTION_NAME, true);
00134   actionlib::SimpleActionClient<arm_navigation_msgs::MoveArmAction> move_arm(MOVE_ARM_ACTION_NAME, true);
00135 
00136   //wait for detection client
00137   while ( !ros::service::waitForService(OBJECT_DETECTION_SERVICE_NAME,
00138                                         ros::Duration(2.0)) && nh.ok() )
00139   {
00140     ROS_INFO("Waiting for object detection service to come up");
00141   }
00142   if (!nh.ok()) exit(0);
00143   object_detection_srv =
00144     nh.serviceClient<tabletop_object_detector::TabletopDetection>
00145     (OBJECT_DETECTION_SERVICE_NAME, true);
00146 
00147   //wait for collision map processing client
00148   while (!ros::service::waitForService(COLLISION_PROCESSING_SERVICE_NAME, ros::Duration(2.0)) && nh.ok())
00149   {
00150     ROS_INFO("Waiting for collision processing service to come up");
00151   }
00152   if (!nh.ok())
00153     exit(0);
00154   collision_processing_srv = nh.serviceClient<tabletop_collision_map_processing::TabletopCollisionMapProcessing>(
00155       COLLISION_PROCESSING_SERVICE_NAME, true);
00156 
00157   //wait for collider reset service
00158   while (!ros::service::waitForService(COLLIDER_RESET_SERVICE_NAME, ros::Duration(2.0)) && nh.ok())
00159   {
00160     ROS_INFO("Waiting for collider reset service to come up");
00161   }
00162   if (!nh.ok())
00163     exit(0);
00164   collider_reset_srv = nh.serviceClient<std_srvs::Empty>(
00165       COLLIDER_RESET_SERVICE_NAME, true);
00166 
00167   //wait for pickup client
00168   while(!pickup_client.waitForServer(ros::Duration(2.0)) && nh.ok())
00169   {
00170     ROS_INFO_STREAM("Waiting for action client " << PICKUP_ACTION_NAME);
00171   }
00172   if (!nh.ok()) exit(0);
00173 
00174   //wait for place client
00175   while(!place_client.waitForServer(ros::Duration(2.0)) && nh.ok())
00176   {
00177     ROS_INFO_STREAM("Waiting for action client " << PLACE_ACTION_NAME);
00178   }
00179   if (!nh.ok()) exit(0);
00180 
00181   //wait for move_arm action client
00182   while(!move_arm.waitForServer(ros::Duration(2.0)) && nh.ok())
00183   {
00184     ROS_INFO_STREAM("Waiting for action client " << MOVE_ARM_ACTION_NAME);
00185   }
00186   if (!nh.ok()) exit(0);
00187 
00188 
00189 
00190 
00191 
00192   // ----- reset collision map
00193   ROS_INFO("Clearing collision map");
00194   std_srvs::Empty empty;
00195   if (!collider_reset_srv.call(empty))
00196   {
00197     ROS_ERROR("Collider reset service failed");
00198     return -1;
00199   }
00200   ros::Duration(5.0).sleep();   // wait for collision map to be completely cleared
00201 
00202   // ----- move arm out of the way
00203   std::vector<std::string> names(NUM_JOINTS);
00204   names[0] = "katana_motor1_pan_joint";
00205   names[1] = "katana_motor2_lift_joint";
00206   names[2] = "katana_motor3_lift_joint";
00207   names[3] = "katana_motor4_lift_joint";
00208   names[4] = "katana_motor5_wrist_roll_joint";
00209 
00210 
00211   std::vector<arm_navigation_msgs::JointConstraint> joint_constraints(NUM_JOINTS);
00212 
00213   for (size_t i = 0; i < NUM_JOINTS; ++i)
00214   {
00215     joint_constraints[i].joint_name = names[i];
00216     joint_constraints[i].tolerance_below = 0.1;
00217     joint_constraints[i].tolerance_above = 0.1;
00218   }
00219 
00220   //  - post_calibration_posture:
00221   //      name: ['katana_motor1_pan_joint', 'katana_motor2_lift_joint', 'katana_motor3_lift_joint', 'katana_motor4_lift_joint', 'katana_motor5_wrist_roll_joint']
00222   //      position: [-2.9641690268167444, 2.13549384276445, -2.1556486321117725, -1.971949347057968, -2.9318804356548496]
00223   //  - arm_away_posture:
00224   //      name: ['katana_motor1_pan_joint', 'katana_motor2_lift_joint', 'katana_motor3_lift_joint', 'katana_motor4_lift_joint', 'katana_motor5_wrist_roll_joint', 'katana_r_finger_joint', 'katana_l_finger_joint']
00225   //      position: [0.0, 2.13549384276445, -2.1556486321117725, -1.971949347057968, 0.0]
00226 
00227   joint_constraints[0].position =  0.0;
00228   joint_constraints[1].position =  2.13549384276445;
00229   joint_constraints[2].position = -2.1556486321117725;
00230   joint_constraints[3].position = -1.971949347057968;
00231   joint_constraints[4].position = 0.0;
00232 
00233   ROS_INFO("Moving arm away");
00234   bool success;
00235   success = move_to_joint_goal(joint_constraints, move_arm);
00236   if (!success)
00237     return -1;
00238 
00239   ros::Duration(2.0).sleep();   // only necessary for Gazebo (the simulated Kinect point cloud lags, so we need to wait for it to settle)
00240 
00241   // ----- reset collision map
00242   ROS_INFO("Clearing collision map");
00243   if (!collider_reset_srv.call(empty))
00244   {
00245     ROS_ERROR("Collider reset service failed");
00246     return -1;
00247   }
00248   ros::Duration(5.0).sleep();   // wait for collision map to be completely cleared
00249 
00250   // ----- call the tabletop detection
00251   ROS_INFO("Calling tabletop detector");
00252   tabletop_object_detector::TabletopDetection detection_call;
00253   //we want recognized database objects returned
00254   //set this to false if you are using the pipeline without the database
00255   detection_call.request.return_clusters = true;
00256   //we want the individual object point clouds returned as well
00257   detection_call.request.return_models = false;
00258   if (!object_detection_srv.call(detection_call))
00259   {
00260     ROS_ERROR("Tabletop detection service failed");
00261     return -1;
00262   }
00263   if (detection_call.response.detection.result !=
00264       detection_call.response.detection.SUCCESS)
00265   {
00266     ROS_ERROR("Tabletop detection returned error code %d",
00267               detection_call.response.detection.result);
00268     return -1;
00269   }
00270   if (detection_call.response.detection.clusters.empty() &&
00271       detection_call.response.detection.models.empty() )
00272   {
00273     ROS_ERROR("The tabletop detector detected the table, but found no objects");
00274     return -1;
00275   }
00276 
00277 
00278   // ----- call collision map processing
00279   ROS_INFO("Calling collision map processing");
00280   tabletop_collision_map_processing::TabletopCollisionMapProcessing
00281     processing_call;
00282   //pass the result of the tabletop detection
00283   processing_call.request.detection_result = detection_call.response.detection;
00284   //ask for the exising map and collision models to be reset
00285   //processing_call.request.reset_static_map = true;
00286   processing_call.request.reset_collision_models = true;
00287   processing_call.request.reset_attached_models = true;
00288   //ask for a new static collision map to be taken with the laser
00289   //after the new models are added to the environment
00290   //processing_call.request.take_static_collision_map = true;
00291   //ask for the results to be returned in base link frame
00292   processing_call.request.desired_frame = "katana_base_link";
00293   if (!collision_processing_srv.call(processing_call))
00294   {
00295     ROS_ERROR("Collision map processing service failed");
00296     return -1;
00297   }
00298   //the collision map processor returns instances of graspable objects
00299   if (processing_call.response.graspable_objects.empty())
00300   {
00301     ROS_ERROR("Collision map processing returned no graspable objects");
00302     return -1;
00303   }
00304 
00305 
00306   // ----- pick up object near point: 25 cm in front and 15 cm to the right of the robot
00307   geometry_msgs::PointStamped pickup_point;
00308   pickup_point.header.frame_id = "/base_footprint";
00309   pickup_point.point.x = 0.25;
00310   pickup_point.point.y = -0.15;
00311   pickup_point.point.z = TABLE_HEIGHT;
00312 
00313   //call object pickup
00314   ROS_INFO("Calling the pickup action");
00315   object_manipulation_msgs::PickupGoal pickup_goal;
00316   //pass one of the graspable objects returned by the collission map processor
00317   int object_to_pick_ind;
00318 
00319   if (!nearest_object(processing_call.response.graspable_objects, pickup_point, object_to_pick_ind))
00320     return -1;
00321   pickup_goal.target = processing_call.response.graspable_objects[object_to_pick_ind];
00322 
00323   //pass the name that the object has in the collision environment
00324   //this name was also returned by the collision map processor
00325   pickup_goal.collision_object_name =
00326     processing_call.response.collision_object_names.at(object_to_pick_ind);
00327   //pass the collision name of the table, also returned by the collision
00328   //map processor
00329   pickup_goal.collision_support_surface_name =
00330     processing_call.response.collision_support_surface_name;
00331   //pick up the object with the right arm
00332   pickup_goal.arm_name = "arm";
00333   pickup_goal.allow_gripper_support_collision = true;
00334   //pickup_goal.desired_approach_distance = 0.06;
00335   //pickup_goal.min_approach_distance = 0.04;
00336 
00337   //we will be lifting the object along the "vertical" direction
00338   //which is along the z axis in the base_link frame
00339   geometry_msgs::Vector3Stamped direction;
00340   direction.header.stamp = ros::Time::now();
00341   direction.header.frame_id = "katana_base_link";
00342   direction.vector.x = 0;
00343   direction.vector.y = 0;
00344   direction.vector.z = 1;
00345   pickup_goal.lift.direction = direction;
00346   //request a vertical lift of 10cm after grasping the object
00347   pickup_goal.lift.desired_distance = 0.1;
00348   pickup_goal.lift.min_distance = 0.05;
00349   //do not use tactile-based grasping or tactile-based lift
00350   pickup_goal.use_reactive_lift = false;
00351   pickup_goal.use_reactive_execution = false;
00352   //send the goal
00353   pickup_client.sendGoal(pickup_goal);
00354   while (!pickup_client.waitForResult(ros::Duration(10.0)))
00355   {
00356     ROS_INFO("Waiting for the pickup action...");
00357     if (!nh.ok())
00358       return -1;
00359   }
00360   object_manipulation_msgs::PickupResult pickup_result = *(pickup_client.getResult());
00361   if (pickup_client.getState() == actionlib::SimpleClientGoalState::SUCCEEDED)
00362   {
00363     ROS_INFO("Pickup succeeded.");
00364   } else
00365   {
00366     ROS_ERROR("The pickup action has failed with result code %d",
00367               pickup_result.manipulation_result.value);
00368     return -1;
00369   }
00370 
00371   //remember where we picked the object up from
00372   geometry_msgs::PoseStamped pickup_location;
00373   //for unrecognized point clouds, the location of the object is considered
00374   //to be the origin of the frame that the cluster is in
00375   pickup_location.header =
00376       processing_call.response.graspable_objects.at(object_to_pick_ind).cluster.header;
00377     //identity pose
00378     pickup_location.pose.orientation.w = 1;
00379 
00380   //create a place location, offset by 30 cm from the pickup location
00381   geometry_msgs::PoseStamped place_location = pickup_location;
00382   place_location.header.stamp = ros::Time::now();
00383   place_location.pose.position.y += 0.3;
00384 
00385   // ----- put the object down
00386   ROS_INFO("Calling the place action");
00387   object_manipulation_msgs::PlaceGoal place_goal;
00388   //place at the prepared location
00389   place_goal.place_locations.push_back(place_location);
00390   //the collision names of both the objects and the table
00391   //same as in the pickup action
00392   place_goal.collision_object_name =
00393     processing_call.response.collision_object_names.at(object_to_pick_ind);
00394   place_goal.collision_support_surface_name =
00395     processing_call.response.collision_support_surface_name;
00396   //information about which grasp was executed on the object, returned by
00397   //the pickup action
00398   place_goal.grasp = pickup_result.grasp;
00399   //use the arm to place
00400   place_goal.arm_name = "arm";
00401   //padding used when determining if the requested place location
00402   //would bring the object in collision with the environment
00403   place_goal.place_padding = 0.02;
00404   //how much the gripper should retreat after placing the object
00405   place_goal.desired_retreat_distance = 0.1;
00406   place_goal.min_retreat_distance = 0.05;
00407   //we will be putting down the object along the "vertical" direction
00408   //which is along the z axis in the base_link frame
00409   direction.header.stamp = ros::Time::now();
00410   direction.header.frame_id = "katana_base_link";
00411   direction.vector.x = 0;
00412   direction.vector.y = 0;
00413   direction.vector.z = -1;
00414   place_goal.approach.direction = direction;
00415   //request a vertical put down motion of 10cm before placing the object
00416   place_goal.approach.desired_distance = 0.1;
00417   place_goal.approach.min_distance = 0.05;
00418   //we are not using tactile based placing
00419   place_goal.use_reactive_place = false;
00420   //send the goal
00421   place_client.sendGoal(place_goal);
00422   while (!place_client.waitForResult(ros::Duration(10.0)))
00423   {
00424     ROS_INFO("Waiting for the place action...");
00425     if (!nh.ok())
00426       return -1;
00427   }
00428   object_manipulation_msgs::PlaceResult place_result =
00429     *(place_client.getResult());
00430   if (place_client.getState() != actionlib::SimpleClientGoalState::SUCCEEDED)
00431   {
00432     if (place_result.manipulation_result.value == object_manipulation_msgs::ManipulationResult::RETREAT_FAILED)
00433     {
00434       ROS_WARN("Place failed with error RETREAT_FAILED, ignoring! This may lead to collision with the object we just placed!");
00435     } else {
00436       ROS_ERROR("Place failed with error code %d",
00437           place_result.manipulation_result.value);
00438       return -1;
00439     }
00440   }
00441 
00442   ros::Duration(2.0).sleep();   // only necessary for Gazebo (the simulated Kinect point cloud lags, so we need to wait for it to settle)
00443 
00444   // ----- reset collision map
00445   ROS_INFO("Clearing collision map");
00446   if (!collider_reset_srv.call(empty))
00447   {
00448     ROS_ERROR("Collider reset service failed");
00449     return -1;
00450   }
00451   ros::Duration(5.0).sleep();   // wait for collision map to be completely cleared
00452 
00453   // ----- move arm away again
00454   ROS_INFO("Moving arm away");
00455   success = move_to_joint_goal(joint_constraints, move_arm);
00456   if (!success)
00457     return -1;
00458 
00459   //success!
00460   ROS_INFO("Success! Object moved.");
00461   return 0;
00462 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Properties Friends


katana_manipulation_tutorials
Author(s): Martin Günther
autogenerated on Tue May 28 2013 15:17:39