pick_and_place_action_server.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2011, Vanadium Labs LLC
3  * All Rights Reserved
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * * Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * * Neither the name of Vanadium Labs LLC nor the names of its
14  * contributors may be used to endorse or promote products derived
15  * from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL VANADIUM LABS BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
23  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
26  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  * Author: Michael Ferguson, Helen Oleynikova
29  */
30 
31 #include <ros/ros.h>
32 #include <tf/tf.h>
33 
35 #include <turtlebot_arm_block_manipulation/PickAndPlaceAction.h>
36 
38 
39 #include <geometry_msgs/PoseArray.h>
40 
42 {
43 
45 {
46 private:
47 
50  std::string action_name_;
51 
52  turtlebot_arm_block_manipulation::PickAndPlaceFeedback feedback_;
53  turtlebot_arm_block_manipulation::PickAndPlaceResult result_;
54  turtlebot_arm_block_manipulation::PickAndPlaceGoalConstPtr goal_;
55 
58 
59  // Move groups to control arm and gripper with MoveIt!
62 
63  // Pick and place parameters
64  std::string arm_link;
65  double gripper_open;
67  double attach_time;
68  double detach_time;
69  double z_up;
70 
71 public:
72  PickAndPlaceServer(const std::string name) :
73  nh_("~"), as_(name, false), action_name_(name), arm_("arm"), gripper_("gripper")
74  {
75  // Read specific pick and place parameters
76  nh_.param("grasp_attach_time", attach_time, 0.8);
77  nh_.param("grasp_detach_time", detach_time, 0.6);
78 
79  // Register the goal and feedback callbacks
80  as_.registerGoalCallback(boost::bind(&PickAndPlaceServer::goalCB, this));
82 
83  as_.start();
84 
85  target_pose_pub_ = nh_.advertise<geometry_msgs::PoseStamped>("/target_pose", 1, true);
86  }
87 
88  void goalCB()
89  {
90  ROS_INFO("[pick and place] Received goal!");
91  goal_ = as_.acceptNewGoal();
92  arm_link = goal_->frame;
93  gripper_open = goal_->gripper_open;
94  gripper_closed = goal_->gripper_closed;
95  z_up = goal_->z_up;
96 
97  arm_.setPoseReferenceFrame(arm_link);
98 
99  // Allow some leeway in position (meters) and orientation (radians)
100  arm_.setGoalPositionTolerance(0.001);
101  arm_.setGoalOrientationTolerance(0.1);
102 
103  // Allow replanning to increase the odds of a solution
104  arm_.allowReplanning(true);
105 
106  if (goal_->topic.length() < 1)
107  pickAndPlace(goal_->pickup_pose, goal_->place_pose);
108  else
109  pick_and_place_sub_ = nh_.subscribe(goal_->topic, 1, &PickAndPlaceServer::sendGoalFromTopic, this);
110  }
111 
112  void sendGoalFromTopic(const geometry_msgs::PoseArrayConstPtr& msg)
113  {
114  ROS_INFO("[pick and place] Got goal from topic! %s", goal_->topic.c_str());
115  pickAndPlace(msg->poses[0], msg->poses[1]);
116  pick_and_place_sub_.shutdown();
117  }
118 
119  void preemptCB()
120  {
121  ROS_INFO("%s: Preempted", action_name_.c_str());
122  // set the action state to preempted
123  as_.setPreempted();
124  }
125 
126  void pickAndPlace(const geometry_msgs::Pose& start_pose, const geometry_msgs::Pose& end_pose)
127  {
128  ROS_INFO("[pick and place] Picking. Also placing.");
129 
130  geometry_msgs::Pose target;
131 
132  /* open gripper */
133  if (setGripper(gripper_open) == false)
134  return;
135 
136  /* hover over */
137  target = start_pose;
138  target.position.z = z_up;
139  if (moveArmTo(target) == false)
140  return;
141 
142  /* go down */
143  target.position.z = start_pose.position.z;
144  if (moveArmTo(target) == false)
145  return;
146 
147  /* close gripper */
148  if (setGripper(gripper_closed) == false)
149  return;
150  ros::Duration(attach_time).sleep(); // ensure that gripper properly grasp the cube before lifting the arm
151 
152  /* go up */
153  target.position.z = z_up;
154  if (moveArmTo(target) == false)
155  return;
156 
157  /* hover over */
158  target = end_pose;
159  target.position.z = z_up;
160  if (moveArmTo(target) == false)
161  return;
162 
163  /* go down */
164  target.position.z = end_pose.position.z;
165  if (moveArmTo(target) == false)
166  return;
167 
168  /* open gripper */
169  if (setGripper(gripper_open) == false)
170  return;
171  ros::Duration(detach_time).sleep(); // ensure that gripper properly release the cube before lifting the arm
172 
173  /* go up */
174  target.position.z = z_up;
175  if (moveArmTo(target) == false)
176  return;
177 
178  as_.setSucceeded(result_);
179  }
180 
181 private:
187  bool moveArmTo(const std::string& target)
188  {
189  ROS_DEBUG("[pick and place] Move arm to '%s' position", target.c_str());
190  if (arm_.setNamedTarget(target) == false)
191  {
192  ROS_ERROR("[pick and place] Set named target '%s' failed", target.c_str());
193  return false;
194  }
195 
197  if (bool(result) == true)
198  {
199  return true;
200  }
201  else
202  {
203  ROS_ERROR("[pick and place] Move to target failed (error %d)", result.val);
204  as_.setAborted(result_);
205  return false;
206  }
207  }
208 
215  bool moveArmTo(const geometry_msgs::Pose& target)
216  {
217  int attempts = 0;
218  ROS_DEBUG("[pick and place] Move arm to [%.2f, %.2f, %.2f, %.2f]",
219  target.position.x, target.position.y, target.position.z, tf::getYaw(target.orientation));
220  while (attempts < 5)
221  {
222  geometry_msgs::PoseStamped modiff_target;
223  modiff_target.header.frame_id = arm_link;
224  modiff_target.pose = target;
225 
226  double x = modiff_target.pose.position.x;
227  double y = modiff_target.pose.position.y;
228  double z = modiff_target.pose.position.z;
229  double d = sqrt(x*x + y*y);
230  if (d > 0.3)
231  {
232  // Maximum reachable distance by the turtlebot arm is 30 cm
233  ROS_ERROR("Target pose out of reach [%f > %f]", d, 0.3);
234  as_.setAborted(result_);
235  return false;
236  }
237  // Pitch is 90 (vertical) at 10 cm from the arm base; the farther the target is, the closer to horizontal
238  // we point the gripper (0.205 = arm's max reach - vertical pitch distance + ε). Yaw is the direction to
239  // the target. We also try some random variations of both to increase the chances of successful planning.
240  // Roll is simply ignored, as our arm lacks the proper dof.
241  double rp = M_PI_2 - std::asin((d - 0.1)/0.205) + attempts*fRand(-0.05, +0.05);
242  double ry = std::atan2(y, x) + attempts*fRand(-0.05, +0.05);
243  double rr = 0.0;
244 
246  tf::quaternionTFToMsg(q, modiff_target.pose.orientation);
247 
248  // Slightly increase z proportionally to pitch to avoid hitting the table with the lower gripper corner
249  ROS_DEBUG("z increase: %f + %f", modiff_target.pose.position.z, std::abs(std::cos(rp))/50.0);
250  modiff_target.pose.position.z += std::abs(std::cos(rp))/50.0;
251 
252  ROS_DEBUG("Set pose target [%.2f, %.2f, %.2f] [d: %.2f, r: %.2f, p: %.2f, y: %.2f]", x, y, z, d, rr, rp, ry);
253  target_pose_pub_.publish(modiff_target);
254 
255  if (arm_.setPoseTarget(modiff_target) == false)
256  {
257  ROS_ERROR("Set pose target [%.2f, %.2f, %.2f, %.2f] failed",
258  modiff_target.pose.position.x, modiff_target.pose.position.y, modiff_target.pose.position.z,
259  tf::getYaw(modiff_target.pose.orientation));
260  as_.setAborted(result_);
261  return false;
262  }
263 
265  if (bool(result) == true)
266  {
267  return true;
268  }
269  else
270  {
271  ROS_ERROR("[pick and place] Move to target failed (error %d) at attempt %d",
272  result.val, attempts + 1);
273  }
274  attempts++;
275  }
276 
277  ROS_ERROR("[pick and place] Move to target failed after %d attempts", attempts);
278  as_.setAborted(result_);
279  return false;
280  }
281 
287  bool setGripper(float opening)
288  {
289  ROS_DEBUG("[pick and place] Set gripper opening to %f", opening);
290  if (gripper_.setJointValueTarget("gripper_joint", opening) == false)
291  {
292  ROS_ERROR("[pick and place] Set gripper opening to %f failed", opening);
293  return false;
294  }
295 
297  if (bool(result) == true)
298  {
299  return true;
300  }
301  else
302  {
303  ROS_ERROR("[pick and place] Set gripper opening failed (error %d)", result.val);
304  as_.setAborted(result_);
305  return false;
306  }
307  }
308 
309  float fRand(float min, float max)
310  {
311  return ((float(rand()) / float(RAND_MAX)) * (max - min)) + min;
312  }
313 };
314 
315 };
316 
317 
318 int main(int argc, char** argv)
319 {
320  ros::init(argc, argv, "pick_and_place_action_server");
321 
323 
324  // Setup an multi-threaded spinner as the move groups operations need continuous spinning
326  spinner.spin();
327 
328  return 0;
329 }
d
boost::shared_ptr< const Goal > acceptNewGoal()
static tf::Quaternion createQuaternionFromRPY(double roll, double pitch, double yaw)
q
void publish(const boost::shared_ptr< M > &message) const
Subscriber subscribe(const std::string &topic, uint32_t queue_size, void(T::*fp)(M), T *obj, const TransportHints &transport_hints=TransportHints())
bool setJointValueTarget(const std::vector< double > &group_variable_values)
turtlebot_arm_block_manipulation::PickAndPlaceResult result_
static double getYaw(const Quaternion &bt_q)
bool sleep() const
turtlebot_arm_block_manipulation::PickAndPlaceFeedback feedback_
ROSCPP_DECL void init(int &argc, char **argv, const std::string &name, uint32_t options=0)
boost::shared_ptr< interactive_markers::InteractiveMarkerServer > server
void setPoseReferenceFrame(const std::string &pose_reference_frame)
actionlib::SimpleActionServer< turtlebot_arm_block_manipulation::PickAndPlaceAction > as_
bool setPoseTarget(const Eigen::Affine3d &end_effector_pose, const std::string &end_effector_link="")
moveit::planning_interface::MoveGroupInterface gripper_
void setGoalOrientationTolerance(double tolerance)
void setSucceeded(const Result &result=Result(), const std::string &text=std::string(""))
double y
void spinner()
#define M_PI_2
void setPreempted(const Result &result=Result(), const std::string &text=std::string(""))
int main(int argc, char **argv)
#define ROS_INFO(...)
bool param(const std::string &param_name, T &param_val, const T &default_val) const
static void quaternionTFToMsg(const Quaternion &bt, geometry_msgs::Quaternion &msg)
void registerPreemptCallback(boost::function< void()> cb)
double z
void pickAndPlace(const geometry_msgs::Pose &start_pose, const geometry_msgs::Pose &end_pose)
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
virtual void spin(CallbackQueue *queue=0)
moveit::planning_interface::MoveGroupInterface arm_
void setAborted(const Result &result=Result(), const std::string &text=std::string(""))
void sendGoalFromTopic(const geometry_msgs::PoseArrayConstPtr &msg)
void registerGoalCallback(boost::function< void()> cb)
double x
#define ROS_ERROR(...)
bool setNamedTarget(const std::string &name)
turtlebot_arm_block_manipulation::PickAndPlaceGoalConstPtr goal_
#define ROS_DEBUG(...)


turtlebot_arm_block_manipulation
Author(s): Michael Ferguson, Helen Oleynikova
autogenerated on Fri Feb 7 2020 03:56:21