pick_server.cpp
Go to the documentation of this file.
00001 #include <ros/ros.h>
00002 #include <moveit/move_group_interface/move_group.h>
00003 #include <moveit/planning_scene_monitor/planning_scene_monitor.h>
00004 #include <actionlib/server/simple_action_server.h>
00005 #include <shape_msgs/SolidPrimitive.h>
00006 #include <shape_tools/shape_extents.h>
00007 #include <calvin_msgs/PickAndStoreAction.h>
00008 #include <tf/tf.h>
00009 #include <tf/transform_listener.h>
00010 #include <moveit_msgs/Grasp.h>
00011 #include <visualization_msgs/Marker.h>
00012 #include <visualization_msgs/MarkerArray.h>
00013 
00014 #include <std_srvs/Empty.h>
00015 
00016 #include <cmath>
00017 
00018 const char* WORK_FRAME = "katana_base_link";
00019 
00020 class PickServer {
00021   protected:
00022     ros::NodeHandle nh;
00023     actionlib::SimpleActionServer<calvin_msgs::PickAndStoreAction> *actionserver;
00024     moveit::planning_interface::MoveGroup *group;
00025     planning_scene_monitor::PlanningSceneMonitorPtr monitor;
00026     ros::ServiceClient clear_octomap;
00027 
00028     ros::Publisher grasps_marker;
00029     tf::TransformListener tfl;
00030 
00031     void publish_grasps_as_markerarray(std::vector<moveit_msgs::Grasp> grasps)
00032     {
00033       visualization_msgs::MarkerArray markers;
00034       int i = 0;
00035 
00036       for(std::vector<moveit_msgs::Grasp>::iterator it = grasps.begin(); it != grasps.end(); ++it) {
00037         visualization_msgs::Marker marker;
00038         marker.header = it->grasp_pose.header;
00039         marker.id = i;
00040         marker.type = 1;
00041         marker.ns = "graspmarker";
00042         marker.pose = it->grasp_pose.pose;
00043         marker.scale.x = 0.02;
00044         marker.scale.y = 0.02;
00045         marker.scale.z = 0.2;
00046         marker.color.b = 1.0;
00047         marker.color.a = 1.0;
00048         markers.markers.push_back(marker);
00049         i++;
00050       }
00051 
00052       grasps_marker.publish(markers);
00053     }
00054 
00055     moveit_msgs::Grasp build_grasp(tf::Transform t, const double close_width)
00056     {
00057       // distance between finger tip and joint
00058       static const double FINGER_LENGTH = 0.078;
00059 
00060       // assert (0 <= close_width && close_width < 2*FINGER_LENGTH );
00061       // angle to set for grasp to produce grasp width 'close_width'
00062       const double close_angle = asin( ( close_width/2 ) / FINGER_LENGTH ) - 0.44;
00063 
00064       static int i = 0;
00065 
00066       moveit_msgs::Grasp grasp;
00067       geometry_msgs::PoseStamped pose;
00068 
00069       tf::Vector3& origin = t.getOrigin();
00070       tf::Quaternion rotation = t.getRotation();
00071 
00072       tf::quaternionTFToMsg(rotation, pose.pose.orientation);
00073 
00074       pose.header.frame_id = WORK_FRAME;
00075       pose.header.stamp = ros::Time::now();
00076       pose.pose.position.x = origin.m_floats[0];
00077       pose.pose.position.y = origin.m_floats[1];
00078       pose.pose.position.z = origin.m_floats[2];
00079       grasp.grasp_pose = pose;
00080 
00081       grasp.id = boost::lexical_cast<std::string>(i);
00082 
00083       grasp.pre_grasp_approach.direction.vector.z = 1.0;
00084       grasp.pre_grasp_approach.direction.header.stamp = ros::Time::now();
00085       grasp.pre_grasp_approach.direction.header.frame_id = "katana_gripper_tool_frame";
00086       grasp.pre_grasp_approach.min_distance = 0.03;
00087       grasp.pre_grasp_approach.desired_distance = 0.07;
00088 
00089       grasp.post_grasp_retreat.direction.vector.z = 1.0;
00090       grasp.post_grasp_retreat.direction.header.stamp = ros::Time::now();
00091       grasp.post_grasp_retreat.direction.header.frame_id = "base_footprint";
00092       grasp.post_grasp_retreat.min_distance = 0.03;
00093       grasp.post_grasp_retreat.desired_distance = 0.07;
00094 
00095       grasp.pre_grasp_posture.joint_names.push_back("katana_l_finger_joint");
00096       grasp.pre_grasp_posture.joint_names.push_back("katana_r_finger_joint");
00097       grasp.pre_grasp_posture.points.resize(1);
00098       grasp.pre_grasp_posture.points[0].positions.push_back(0.3);
00099       grasp.pre_grasp_posture.points[0].positions.push_back(0.3);
00100 
00101       grasp.grasp_posture.joint_names.push_back("katana_l_finger_joint");
00102       grasp.grasp_posture.joint_names.push_back("katana_r_finger_joint");
00103       grasp.grasp_posture.points.resize(1);
00104       grasp.grasp_posture.points[0].positions.push_back(close_angle);
00105       grasp.grasp_posture.points[0].positions.push_back(close_angle);
00106 
00107       i++;
00108       return grasp;
00109     }
00110 
00115     std::vector<moveit_msgs::Grasp> generate_grasps(double x, double y, double z, const double width, bool no_straight_grasps)
00116     {
00117       static const double ANGLE_INC = M_PI / 16;
00118       static const double STRAIGHT_ANGLE_MIN = 0.0 + ANGLE_INC;  // + ANGLE_INC, because 0 is already covered by side grasps
00119       static const double ANGLE_MAX = M_PI / 2;
00120 
00121       // how far from the grasp center should the wrist be?
00122       static const double STANDOFF = -0.01;
00123 
00124       std::vector<moveit_msgs::Grasp> grasps;
00125 
00126       tf::Transform transform;
00127 
00128       tf::Transform standoff_trans;
00129       standoff_trans.setOrigin(tf::Vector3(STANDOFF, 0.0, 0.0));
00130       standoff_trans.setRotation(tf::Quaternion(0.0, sqrt(2)/2, 0.0, sqrt(2)/2));
00131 
00132       // ----- side grasps
00133       //
00134       //  1. side grasp (xy-planes of `katana_motor5_wrist_roll_link` and of `katana_base_link` are parallel):
00135       //     - standard: `rpy = (0, 0, *)` (orientation of `katana_motor5_wrist_roll_link` in `katana_base_link` frame)
00136       //     - overhead: `rpy = (pi, 0, *)`
00137       transform.setOrigin(tf::Vector3(x, y, z));
00138 
00139       for (double roll = 0.0; roll <= M_PI; roll += M_PI)
00140       {
00141         double pitch = 0.0;
00142 
00143         // add yaw = 0 first, then +ANGLE_INC, -ANGLE_INC, 2*ANGLE_INC, ...
00144         // reason: grasps with yaw near 0 mean that the approach is from the
00145         // direction of the arm; it is usually easier to place the object back like
00146         // this
00147         for (double yaw = ANGLE_INC; yaw <= ANGLE_MAX; yaw += ANGLE_INC)
00148         {
00149           // + atan2 to center the grasps around the vector from arm to object
00150           transform.setRotation(tf::createQuaternionFromRPY(roll, pitch, yaw + atan2(y, x)));
00151           grasps.push_back(build_grasp(transform * standoff_trans, width));
00152 
00153           if (yaw != 0.0)
00154           {
00155             transform.setRotation(tf::createQuaternionFromRPY(roll, pitch, -yaw + atan2(y, x)));
00156             grasps.push_back(build_grasp(transform * standoff_trans, width));
00157           }
00158         }
00159       }
00160 
00161       if (!no_straight_grasps)
00162       {
00163         // ----- straight grasps
00164         //
00165         //  2. straight grasp (xz-plane of `katana_motor5_wrist_roll_link` contains z axis of `katana_base_link`)
00166         //     - standard: `rpy = (0, *, atan2(y_w, x_w))`   (x_w, y_w = position of `katana_motor5_wrist_roll_link` in `katana_base_link` frame)
00167         //     - overhead: `rpy = (pi, *, atan2(y_w, x_w))`
00168         for (double roll = 0.0; roll <= M_PI; roll += M_PI)
00169         {
00170           for (double pitch = STRAIGHT_ANGLE_MIN; pitch <= ANGLE_MAX; pitch += ANGLE_INC)
00171           {
00172             double yaw = atan2(y, x);
00173             transform.setOrigin(tf::Vector3(x, y, z));
00174             transform.setRotation(tf::createQuaternionFromRPY(roll, pitch, yaw));
00175 
00176             grasps.push_back(build_grasp(transform * standoff_trans, width));
00177           }
00178         }
00179       }
00180 
00181       return grasps;
00182     }
00183   public:
00184     PickServer(std::string name) {
00185       group = new moveit::planning_interface::MoveGroup("arm");
00186       group->setPlanningTime(120.0);
00187       monitor.reset( new planning_scene_monitor::PlanningSceneMonitor("robot_description") );
00188       clear_octomap = nh.serviceClient<std_srvs::Empty>("/clear_octomap");
00189 
00190       actionserver = new actionlib::SimpleActionServer<calvin_msgs::PickAndStoreAction>(nh, ros::names::resolve(name), boost::bind(&PickServer::pick, this, _1), false);
00191       grasps_marker = nh.advertise<visualization_msgs::MarkerArray>("grasps_marker", 10);
00192       actionserver->start();
00193     }
00194     ~PickServer() {
00195       delete actionserver;
00196       delete group;
00197     }
00198     void pick(const calvin_msgs::PickAndStoreGoalConstPtr &goal) {
00199       // maximum width of grasp (can't grasp anything bigger than this)
00200       static const double MAX_GRASP_WIDTH = 0.10;
00201 
00202       static const double SQUEEZE_FACTOR = 0.55;
00203 
00204       if(goal->co.primitive_poses.size() != 1 || goal->co.primitives.size() != 1){
00205         ROS_ERROR("PickAndStore requires a CollisionObject with exactly one SolidPrimitive. Aborting.");
00206         actionserver->setAborted();
00207         return;
00208       }
00209 
00210       geometry_msgs::PoseStamped co_pose;
00211       co_pose.header = goal->co.header;
00212       co_pose.pose = goal->co.primitive_poses[0];
00213       try {
00214         if(!tfl.waitForTransform(WORK_FRAME, goal->co.header.frame_id, goal->co.header.stamp, ros::Duration(5.0))){
00215           throw tf::TransformException("waiting for transform failed or timed out");
00216         }
00217         tfl.transformPose(WORK_FRAME, co_pose, co_pose);
00218       }
00219       catch (const tf::TransformException& e){
00220         ROS_ERROR("PickAndStore could not transform object into '%s' frame", WORK_FRAME);
00221         actionserver->setAborted();
00222         return;
00223       }
00224 
00225       double x = co_pose.pose.position.x;
00226       double y = co_pose.pose.position.y;
00227       double z = co_pose.pose.position.z;
00228 
00229       double width = 0.0;
00230       if( goal->close_gripper_partially ){
00231         // compute object 'width'
00232         // TODO: This ignores different object sizes from different approach directions and uses the front width for all of them
00233         double object_width, dx, dz;
00234         shape_tools::getShapeExtents(goal->co.primitives[0], dx, object_width, dz);
00235 
00236         width= SQUEEZE_FACTOR * object_width;
00237         if(0.0 > width || width > MAX_GRASP_WIDTH){
00238           width= std::min( MAX_GRASP_WIDTH, std::max(0.0, width) );
00239           ROS_WARN("Trying to pick an object which is too big to grasp (%fm), trying to pick with grasp width %fm", object_width, width);
00240         }
00241       }
00242 
00243       std::string id = goal->co.id;
00244       ROS_INFO("Trying to pick object %s at %f, %f, %f.", id.c_str(), x, y, z);
00245       bool result = group->pick(id, generate_grasps(x, y, z, width, goal->disable_straight_grasps));
00246 
00247       // if pick did not succeed, but object got attached, place it anyway
00248 
00249       if(!result){
00250         monitor->requestPlanningSceneState();
00251         planning_scene_monitor::LockedPlanningSceneRO scene(monitor);
00252         const robot_state::RobotState& state = scene->getCurrentState();
00253         if(state.hasAttachedBody(id)){
00254           ROS_WARN("move_group::pick reported failure, but apparently the object got picked. Placing anyway");
00255           std_srvs::Empty srv;
00256           clear_octomap.call(srv);
00257           result = true;
00258         }
00259       }
00260 
00261       if(result) {
00262           ROS_INFO("Pick Action succeeded. Trying to Place.");
00263           bool result = place(id);
00264           if(result) {
00265               ROS_INFO("Place Action succeeded.");
00266               actionserver->setSucceeded();
00267           }
00268           else {
00269               ROS_WARN("Place Action failed. Aborting.");
00270               actionserver->setAborted();
00271           }
00272       }
00273       else {
00274           ROS_WARN("Pick Action failed. Aborting.");
00275           actionserver->setAborted();
00276       }
00277     }
00278     bool place(std::string id) {
00279       static const double ANGLE_INC = M_PI / 16;
00280 
00281       std::vector<moveit_msgs::PlaceLocation> loc;
00282 
00283       for (double yaw = -M_PI; yaw < M_PI; yaw += ANGLE_INC)
00284       {
00285         geometry_msgs::PoseStamped p;
00286         p.header.frame_id = WORK_FRAME;
00287         p.pose.position.x = 0.135;
00288         p.pose.position.y = 0.115;
00289         p.pose.position.z = -0.018;
00290         tf::quaternionTFToMsg(tf::createQuaternionFromRPY(0.0, 0.0, yaw), p.pose.orientation);
00291 
00292         moveit_msgs::PlaceLocation g;
00293         g.place_pose = p;
00294 
00295         g.pre_place_approach.direction.vector.z = -1.0;
00296         g.pre_place_approach.direction.header.frame_id = "base_footprint";
00297         g.pre_place_approach.min_distance = 0.03;
00298         g.pre_place_approach.desired_distance = 0.07;
00299         g.post_place_retreat.direction.vector.z = 1.0;
00300         g.post_place_retreat.direction.header.frame_id = "base_footprint";
00301         g.post_place_retreat.min_distance = 0.03;
00302         g.post_place_retreat.desired_distance = 0.07;
00303 
00304         g.post_place_posture.joint_names.push_back("katana_l_finger_joint");
00305         g.post_place_posture.joint_names.push_back("katana_r_finger_joint");
00306         g.post_place_posture.points.resize(1);
00307         g.post_place_posture.points[0].positions.push_back(0.3);
00308         g.post_place_posture.points[0].positions.push_back(0.3);
00309 
00310         loc.push_back(g);
00311       }
00312 
00313       group->setSupportSurfaceName("cup");
00314 
00315       return group->place(id, loc);
00316     }
00317 };
00318 
00319 
00320 int main(int argc, char **argv) {
00321   ros::init (argc, argv, "calvin_pick_server");
00322   PickServer pickserver("calvin_pick_and_store");
00323   ros::spin();
00324   return 0;
00325 }


calvin_pick_server
Author(s): Michael Stypa
autogenerated on Thu Jun 6 2019 17:38:53