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
00058 static const double FINGER_LENGTH = 0.078;
00059
00060
00061
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;
00119 static const double ANGLE_MAX = M_PI / 2;
00120
00121
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
00133
00134
00135
00136
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
00144
00145
00146
00147 for (double yaw = ANGLE_INC; yaw <= ANGLE_MAX; yaw += ANGLE_INC)
00148 {
00149
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
00164
00165
00166
00167
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
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
00232
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
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 }