00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031 #include <ros/ros.h>
00032 #include <tf/tf.h>
00033
00034 #include <actionlib/server/simple_action_server.h>
00035 #include <turtlebot_arm_block_manipulation/PickAndPlaceAction.h>
00036
00037 #include <moveit/move_group_interface/move_group.h>
00038
00039 #include <geometry_msgs/PoseArray.h>
00040
00041 namespace turtlebot_arm_block_manipulation
00042 {
00043
00044 class PickAndPlaceServer
00045 {
00046 private:
00047
00048 ros::NodeHandle nh_;
00049 actionlib::SimpleActionServer<turtlebot_arm_block_manipulation::PickAndPlaceAction> as_;
00050 std::string action_name_;
00051
00052 turtlebot_arm_block_manipulation::PickAndPlaceFeedback feedback_;
00053 turtlebot_arm_block_manipulation::PickAndPlaceResult result_;
00054 turtlebot_arm_block_manipulation::PickAndPlaceGoalConstPtr goal_;
00055
00056 ros::Publisher target_pose_pub_;
00057 ros::Subscriber pick_and_place_sub_;
00058
00059
00060 moveit::planning_interface::MoveGroup arm_;
00061 moveit::planning_interface::MoveGroup gripper_;
00062
00063
00064 std::string arm_link;
00065 double gripper_open;
00066 double gripper_closed;
00067 double z_up;
00068
00069 public:
00070 PickAndPlaceServer(const std::string name) :
00071 nh_("~"), as_(name, false), action_name_(name), arm_("arm"), gripper_("gripper")
00072 {
00073
00074 as_.registerGoalCallback(boost::bind(&PickAndPlaceServer::goalCB, this));
00075 as_.registerPreemptCallback(boost::bind(&PickAndPlaceServer::preemptCB, this));
00076
00077 as_.start();
00078
00079 target_pose_pub_ = nh_.advertise<geometry_msgs::PoseStamped>("/target_pose", 1, true);
00080 }
00081
00082 void goalCB()
00083 {
00084 ROS_INFO("[pick and place] Received goal!");
00085 goal_ = as_.acceptNewGoal();
00086 arm_link = goal_->frame;
00087 gripper_open = goal_->gripper_open;
00088 gripper_closed = goal_->gripper_closed;
00089 z_up = goal_->z_up;
00090
00091 arm_.setPoseReferenceFrame(arm_link);
00092
00093
00094 arm_.setGoalOrientationTolerance(0.001);
00095 arm_.setGoalOrientationTolerance(0.1);
00096
00097
00098 arm_.allowReplanning(true);
00099
00100 if (goal_->topic.length() < 1)
00101 pickAndPlace(goal_->pickup_pose, goal_->place_pose);
00102 else
00103 pick_and_place_sub_ = nh_.subscribe(goal_->topic, 1, &PickAndPlaceServer::sendGoalFromTopic, this);
00104 }
00105
00106 void sendGoalFromTopic(const geometry_msgs::PoseArrayConstPtr& msg)
00107 {
00108 ROS_INFO("[pick and place] Got goal from topic! %s", goal_->topic.c_str());
00109 pickAndPlace(msg->poses[0], msg->poses[1]);
00110 pick_and_place_sub_.shutdown();
00111 }
00112
00113 void preemptCB()
00114 {
00115 ROS_INFO("%s: Preempted", action_name_.c_str());
00116
00117 as_.setPreempted();
00118 }
00119
00120 void pickAndPlace(const geometry_msgs::Pose& start_pose, const geometry_msgs::Pose& end_pose)
00121 {
00122 ROS_INFO("[pick and place] Picking. Also placing.");
00123
00124 geometry_msgs::Pose target;
00125
00126
00127 if (setGripper(gripper_open) == false)
00128 return;
00129
00130
00131 target = start_pose;
00132 target.position.z = z_up;
00133 if (moveArmTo(target) == false)
00134 return;
00135
00136
00137 target.position.z = start_pose.position.z;
00138 if (moveArmTo(target) == false)
00139 return;
00140
00141
00142 if (setGripper(gripper_closed) == false)
00143 return;
00144 ros::Duration(0.8).sleep();
00145
00146
00147 target.position.z = z_up;
00148 if (moveArmTo(target) == false)
00149 return;
00150
00151
00152 target = end_pose;
00153 target.position.z = z_up;
00154 if (moveArmTo(target) == false)
00155 return;
00156
00157
00158 target.position.z = end_pose.position.z;
00159 if (moveArmTo(target) == false)
00160 return;
00161
00162
00163 if (setGripper(gripper_open) == false)
00164 return;
00165 ros::Duration(0.6).sleep();
00166
00167
00168 target.position.z = z_up;
00169 if (moveArmTo(target) == false)
00170 return;
00171
00172 as_.setSucceeded(result_);
00173 }
00174
00175
00181 bool moveArmTo(const std::string& target)
00182 {
00183 ROS_DEBUG("[pick and place] Move arm to '%s' position", target.c_str());
00184 if (arm_.setNamedTarget(target) == false)
00185 {
00186 ROS_ERROR("[pick and place] Set named target '%s' failed", target.c_str());
00187 return false;
00188 }
00189
00190 moveit::planning_interface::MoveItErrorCode result = arm_.move();
00191 if (bool(result) == true)
00192 {
00193 return true;
00194 }
00195 else
00196 {
00197 ROS_ERROR("[pick and place] Move to target failed (error %d)", result.val);
00198 as_.setAborted(result_);
00199 return false;
00200 }
00201 }
00202
00209 bool moveArmTo(const geometry_msgs::Pose& target)
00210 {
00211 int attempts = 0;
00212 ROS_DEBUG("[pick and place] Move arm to [%.2f, %.2f, %.2f, %.2f]",
00213 target.position.x, target.position.y, target.position.z, tf::getYaw(target.orientation));
00214 while (attempts < 5)
00215 {
00216 geometry_msgs::PoseStamped modiff_target;
00217 modiff_target.header.frame_id = arm_link;
00218 modiff_target.pose = target;
00219
00220 double x = modiff_target.pose.position.x;
00221 double y = modiff_target.pose.position.y;
00222 double z = modiff_target.pose.position.z;
00223 double d = sqrt(x*x + y*y);
00224 if (d > 0.3)
00225 {
00226
00227 ROS_ERROR("Target pose out of reach [%f > %f]", d, 0.3);
00228 as_.setAborted(result_);
00229 return false;
00230 }
00231
00232
00233 double rp = M_PI_2 - asin((d - 0.1)/0.205);
00234 double ry = asin(y/d);
00235
00236 tf::Quaternion q = tf::createQuaternionFromRPY(0.0,
00237 attempts*fRand(-0.05, +0.05) + rp,
00238 attempts*fRand(-0.05, +0.05) + ry);
00239 ROS_DEBUG("Set pose target [%.2f, %.2f, %.2f] [d: %.2f, p: %.2f, y: %.2f]", x, y, z, d, rp, ry);
00240 tf::quaternionTFToMsg(q, modiff_target.pose.orientation);
00241
00242 target_pose_pub_.publish(modiff_target);
00243
00244 if (arm_.setPoseTarget(modiff_target) == false)
00245 {
00246 ROS_ERROR("Set pose target [%.2f, %.2f, %.2f, %.2f] failed",
00247 modiff_target.pose.position.x, modiff_target.pose.position.y, modiff_target.pose.position.z,
00248 tf::getYaw(modiff_target.pose.orientation));
00249 as_.setAborted(result_);
00250 return false;
00251 }
00252
00253 moveit::planning_interface::MoveItErrorCode result = arm_.move();
00254 if (bool(result) == true)
00255 {
00256 return true;
00257 }
00258 else
00259 {
00260 ROS_ERROR("[pick and place] Move to target failed (error %d) at attempt %d",
00261 result.val, attempts + 1);
00262 }
00263 attempts++;
00264 }
00265
00266 ROS_ERROR("[pick and place] Move to target failed after %d attempts", attempts);
00267 as_.setAborted(result_);
00268 return false;
00269 }
00270
00276 bool setGripper(float opening)
00277 {
00278 ROS_DEBUG("[pick and place] Set gripper opening to %f", opening);
00279 if (gripper_.setJointValueTarget("gripper_joint", opening) == false)
00280 {
00281 ROS_ERROR("[pick and place] Set gripper opening to %f failed", opening);
00282 return false;
00283 }
00284
00285 moveit::planning_interface::MoveItErrorCode result = gripper_.move();
00286 if (bool(result) == true)
00287 {
00288 return true;
00289 }
00290 else
00291 {
00292 ROS_ERROR("[pick and place] Set gripper opening failed (error %d)", result.val);
00293 as_.setAborted(result_);
00294 return false;
00295 }
00296 }
00297
00298
00299 float fRand(float min, float max)
00300 {
00301 return ((float(rand()) / float(RAND_MAX)) * (max - min)) + min;
00302 }
00303 };
00304
00305 };
00306
00307
00308 int main(int argc, char** argv)
00309 {
00310 ros::init(argc, argv, "pick_and_place_action_server");
00311
00312
00313 ros::AsyncSpinner spinner(2);
00314 spinner.start();
00315
00316 turtlebot_arm_block_manipulation::PickAndPlaceServer server("pick_and_place");
00317 ros::spin();
00318
00319 spinner.stop();
00320 return 0;
00321 }