pick_and_place_action_server.cpp
Go to the documentation of this file.
00001 /* 
00002  * Copyright (c) 2011, Vanadium Labs LLC
00003  * All Rights Reserved
00004  * 
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions are met:
00007  *
00008  *     * Redistributions of source code must retain the above copyright
00009  *       notice, this list of conditions and the following disclaimer.
00010  *     * Redistributions in binary form must reproduce the above copyright
00011  *       notice, this list of conditions and the following disclaimer in the
00012  *       documentation and/or other materials provided with the distribution.
00013  *     * Neither the name of Vanadium Labs LLC nor the names of its 
00014  *       contributors may be used to endorse or promote products derived 
00015  *       from this software without specific prior written permission.
00016  * 
00017  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
00018  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00019  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00020  * DISCLAIMED. IN NO EVENT SHALL VANADIUM LABS BE LIABLE FOR ANY DIRECT, INDIRECT,
00021  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
00022  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
00023  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00024  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
00025  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
00026  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00027  * 
00028  * Author: Michael Ferguson, Helen Oleynikova
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   // Move groups to control arm and gripper with MoveIt!
00060   moveit::planning_interface::MoveGroup arm_;
00061   moveit::planning_interface::MoveGroup gripper_;
00062   
00063   // Parameters from goal
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     // Register the goal and feedback callbacks
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     // Allow some leeway in position (meters) and orientation (radians)
00094     arm_.setGoalOrientationTolerance(0.001);
00095     arm_.setGoalOrientationTolerance(0.1);
00096 
00097     // Allow replanning to increase the odds of a solution
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     // set the action state to preempted
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     /* open gripper */
00127     if (setGripper(gripper_open) == false)
00128       return;
00129 
00130     /* hover over */
00131     target = start_pose;
00132     target.position.z = z_up;
00133     if (moveArmTo(target) == false)
00134       return;
00135 
00136     /* go down */
00137     target.position.z = start_pose.position.z;
00138     if (moveArmTo(target) == false)
00139       return;
00140 
00141     /* close gripper */
00142     if (setGripper(gripper_closed) == false)
00143       return;
00144     ros::Duration(0.8).sleep(); // ensure that gripper properly grasp the cube before lifting the arm
00145 
00146     /* go up */
00147     target.position.z = z_up;
00148     if (moveArmTo(target) == false)
00149       return;
00150 
00151     /* hover over */
00152     target = end_pose;
00153     target.position.z = z_up;
00154     if (moveArmTo(target) == false)
00155       return;
00156 
00157     /* go down */
00158     target.position.z = end_pose.position.z;
00159     if (moveArmTo(target) == false)
00160       return;
00161 
00162     /* open gripper */
00163     if (setGripper(gripper_open) == false)
00164       return;
00165     ros::Duration(0.6).sleep(); // ensure that gripper properly release the cube before lifting the arm
00166 
00167     /* go up */
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         // Maximum reachable distance by the turtlebot arm is 30 cm
00227         ROS_ERROR("Target pose out of reach [%f > %f]", d, 0.3);
00228         as_.setAborted(result_);
00229         return false;
00230       }
00231       // Pitch is 90 (vertical) at 10 cm, the more horizontal the farer the target is. Yaw is the direction
00232       // to the target. We tried randomly variations of both to increase the chances of successful planning
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   // Setup an asynchronous spinner as the move groups operations need continuous spinning
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 }


turtlebot_arm_block_manipulation
Author(s): Michael Ferguson, Helen Oleynikova
autogenerated on Thu Jun 6 2019 20:54:14