$search
00001 #!/usr/bin/python 00002 # Software License Agreement (BSD License) 00003 # 00004 # Copyright (c) 2009, Willow Garage, Inc. 00005 # All rights reserved. 00006 # 00007 # Redistribution and use in source and binary forms, with or without 00008 # modification, are permitted provided that the following conditions 00009 # are met: 00010 # 00011 # * Redistributions of source code must retain the above copyright 00012 # notice, this list of conditions and the following disclaimer. 00013 # * Redistributions in binary form must reproduce the above 00014 # copyright notice, this list of conditions and the following 00015 # disclaimer in the documentation and/or other materials provided 00016 # with the distribution. 00017 # * Neither the name of the Willow Garage nor the names of its 00018 # contributors may be used to endorse or promote products derived 00019 # from this software without specific prior written permission. 00020 # 00021 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 00022 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 00023 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 00024 # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 00025 # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 00026 # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 00027 # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 00028 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 00029 # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 00030 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 00031 # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00032 # POSSIBILITY OF SUCH DAMAGE. 00033 # 00034 # author: Kaijen Hsiao 00035 00036 ## @package reactive_grasp_server 00037 #Actions and services for reactive grasp, reactive approach, reactive lift, 00038 #compliant close, and grasp adjustment. 00039 00040 from __future__ import division 00041 import roslib; roslib.load_manifest('pr2_gripper_reactive_approach') 00042 import rospy 00043 import pr2_gripper_reactive_approach.reactive_grasp as reactive_grasp 00044 import pr2_gripper_reactive_approach.controller_manager as controller_manager 00045 import sys 00046 import math 00047 from object_manipulation_msgs.msg import ReactiveGraspAction, ReactiveGraspResult, \ 00048 ManipulationResult, GripperTranslation, ReactiveLiftAction, ReactiveLiftResult, \ 00049 ReactivePlaceAction, ReactivePlaceResult, ReactiveGraspFeedback, \ 00050 ReactiveLiftFeedback, ReactivePlaceFeedback, ManipulationPhase 00051 from object_manipulator.convert_functions import * 00052 from std_srvs.srv import Empty, EmptyResponse 00053 import actionlib 00054 import pdb 00055 import time 00056 00057 ##preempt exception 00058 class Preempted(Exception): pass 00059 00060 ##reactive grasp class with overloaded preempt 00061 class ReactiveGrasperWithPreempt(reactive_grasp.ReactiveGrasper): 00062 00063 def __init__(self, cm, rg_as, lift_as, approach_as, place_as): 00064 00065 reactive_grasp.ReactiveGrasper.__init__(self, cm) 00066 00067 #add the action servers so we can check for preempts and send feedback 00068 self._rg_as = rg_as 00069 self._lift_as = lift_as 00070 self._approach_as = approach_as 00071 self._place_as = place_as 00072 00073 self.rg_state = "off" 00074 00075 self.pause_for_recording = 0 00076 00077 00078 ##overloaded to add action preempts 00079 def check_preempt(self): 00080 00081 if self.rg_state == "rg" and self._rg_as.is_preempt_requested() or \ 00082 self.rg_state == "lift" and self._lift_as.is_preempt_requested() or \ 00083 self.rg_state == "approach" and self._approach_as.is_preempt_requested() or \ 00084 self.rg_state == "place" and self._place_as.is_preempt_requested(): 00085 00086 rospy.loginfo("preempt seen, state=%s"%self.rg_state) 00087 00088 #switch back to joint controllers so we're not left in a bad state 00089 rospy.loginfo("switching back to joint controllers") 00090 self.cm.switch_to_joint_mode() 00091 00092 raise Preempted 00093 00094 ##overloaded to add feedback broadcasts 00095 def broadcast_phase(self, phase, send_feedback = 1): 00096 self._phase_pub.publish(phase) 00097 00098 if self.rg_state == "rg": 00099 feedback = ReactiveGraspFeedback() 00100 feedback.manipulation_phase.phase = phase 00101 self._rg_as.publish_feedback(feedback) 00102 elif self.rg_state == "lift": 00103 feedback = ReactiveLiftFeedback() 00104 feedback.manipulation_phase.phase = phase 00105 self._lift_as.publish_feedback(feedback) 00106 elif self.rg_state == "place": 00107 feedback = ReactivePlaceFeedback() 00108 feedback.manipulation_phase.phase = phase 00109 self._place_as.publish_feedback(feedback) 00110 00111 #if recording in the grasp playpen, pause at MOVING_TO_GRASP or PLACING 00112 #for the recorder to finish broadcasting 00113 if self.pause_for_recording and (phase == ManipulationPhase.MOVING_TO_GRASP \ 00114 or phase == ManipulationPhase.PLACING): 00115 time.sleep(3) 00116 00117 00118 00119 ##Class for the reactive grasp actions and services 00120 class ReactiveGraspActionServer(object): 00121 _grasp_result = ReactiveGraspResult() 00122 _lift_result = ReactiveLiftResult() 00123 _place_result = ReactivePlaceResult() 00124 00125 def __init__(self, which_arm): #which_arm is 'r' or 'l' 00126 self.which_arm = which_arm 00127 00128 self._node_name = which_arm+'_reactive_grasp' 00129 if which_arm == 'r': 00130 self._action_name = 'reactive_grasp/right' 00131 self._lift_action_name = 'reactive_lift/right' 00132 self._approach_action_name = 'reactive_approach/right' 00133 self._place_action_name = 'reactive_place/right' 00134 else: 00135 self._action_name = 'reactive_grasp/left' 00136 self._lift_action_name = 'reactive_lift/left' 00137 self._approach_action_name = 'reactive_approach/left' 00138 self._place_action_name = 'reactive_place/left' 00139 00140 #params for reactive approach/grasp 00141 self.side_step = rospy.get_param("~side_step", .015) 00142 self.back_step = rospy.get_param("~back_step", .03) 00143 self.approach_num_tries = rospy.get_param("~approach_num_tries", 5) 00144 self.goal_pos_thres = rospy.get_param("~goal_pos_thres", .01) 00145 00146 #params for reactive grasp/grasp adjustment 00147 self.min_contact_row = rospy.get_param("~min_contact_row", 1) 00148 self.min_gripper_opening = rospy.get_param("~min_gripper_opening", .0021) 00149 self.max_gripper_opening = rospy.get_param("~max_gripper_opening", .1) 00150 self.grasp_adjust_x_step = rospy.get_param("~grasp_adjust_x_step", .02) 00151 self.grasp_adjust_z_step = rospy.get_param("~grasp_adjust_z_step", .015) 00152 self.grasp_adjust_num_tries = rospy.get_param("~grasp_adjust_num_tries", 3) 00153 00154 #params for reactive grasp 00155 self.grasp_num_tries = rospy.get_param("~grasp_num_tries", 2) 00156 self.forward_step = rospy.get_param("~forward_step", 0) #select based on top/side 00157 self.close_force = rospy.get_param("~close_force", 100) 00158 self.use_slip_controller = rospy.get_param("~use_slip_controller", 0) 00159 self.use_slip_detection = rospy.get_param("~use_slip_detection", 0) 00160 00161 #params for reactive place 00162 self.place_overshoot = rospy.get_param("~place_overshoot", .01) 00163 self.place_angle_max_diff = rospy.get_param("~place_angle_max_diff", math.pi/10.) 00164 00165 #params for reactive lift 00166 self.shake_object = rospy.get_param("~shake_object", 0) 00167 00168 rospy.loginfo("reactive_grasp_server: using_slip_controller:"+str(self.use_slip_controller)) 00169 rospy.loginfo("reactive_grasp_server: using_slip_detection:"+str(self.use_slip_detection)) 00170 00171 #param for recording in grasp_playpen 00172 self.pause_for_recording = rospy.get_param("~pause_for_recording", 0) 00173 00174 if self.pause_for_recording: 00175 rospy.loginfo("pausing for recording is turned on") 00176 00177 #start action servers for reactive grasp, lift, and approach 00178 self._as = actionlib.SimpleActionServer(self._action_name, ReactiveGraspAction, \ 00179 execute_cb=self.reactive_grasp_cb) 00180 self._lift_as = actionlib.SimpleActionServer(self._lift_action_name, ReactiveLiftAction, \ 00181 execute_cb=self.reactive_lift_cb) 00182 self._approach_as = actionlib.SimpleActionServer(self._approach_action_name, ReactiveGraspAction, \ 00183 execute_cb = self.reactive_approach_cb) 00184 self._place_as = actionlib.SimpleActionServer(self._place_action_name, ReactivePlaceAction, \ 00185 execute_cb = self.reactive_place_cb) 00186 00187 #advertise services for compliant grasp and grasp adjustment 00188 rospy.Service(self._node_name+'/compliant_close', \ 00189 Empty, self.compliant_close_callback) 00190 rospy.Service(self._node_name+'/grasp_adjustment', \ 00191 Empty, self.grasp_adjustment_callback) 00192 00193 #initialize controler manager and reactive grasper 00194 self.cm = controller_manager.ControllerManager(which_arm, \ 00195 using_slip_controller = self.use_slip_controller, \ 00196 using_slip_detection = self.use_slip_detection) 00197 self.rg = ReactiveGrasperWithPreempt(self.cm, self._as, self._lift_as, self._approach_as, self._place_as) 00198 00199 #shove the flag into the reactive grasper 00200 self.rg.pause_for_recording = self.pause_for_recording 00201 00202 00203 ##do a reactive grasp using the fingertip sensors 00204 #(backs up and moves to the side if a fingertip contacts on the way to the grasp, 00205 #closes compliantly, tries approach and grasp again if gripper opening is not within bounds) 00206 def reactive_grasp_cb(self, goal): 00207 00208 rospy.loginfo("got reactive grasp request") 00209 try: 00210 self.rg_state = "rg" 00211 (trajectory, object_name, table_name, forward_step) = self.init_reactive_grasp(goal) 00212 00213 #perform the reactive grasp 00214 self.cm.switch_to_cartesian_mode() 00215 if goal.max_contact_force > 0: 00216 self.rg.close_force = goal.max_contact_force 00217 result = self.rg.reactive_grasp(None, goal.final_grasp_pose, trajectory, \ 00218 self.side_step, self.back_step, \ 00219 self.approach_num_tries, self.goal_pos_thres, \ 00220 self.min_gripper_opening, self.max_gripper_opening, \ 00221 self.grasp_num_tries, forward_step, self.min_contact_row, \ 00222 object_name, table_name, \ 00223 self.grasp_adjust_x_step, self.grasp_adjust_z_step, self.grasp_adjust_num_tries) 00224 self.rg.check_preempt() 00225 00226 rospy.loginfo("switching back to joint controllers") 00227 self.cm.switch_to_joint_mode() 00228 self.rg_state = "off" 00229 00230 if result == 0: 00231 self.rg.broadcast_phase(ManipulationPhase.SUCCEEDED, send_feedback = 0) 00232 self._grasp_result.manipulation_result.value = ManipulationResult.SUCCESS 00233 self._as.set_succeeded(self._grasp_result) 00234 else: 00235 #stopped reporting 'failed' just in case we're grasping a super-thin object--it's up to the next-level-up app to decide whether we succeeded 00236 self.rg.broadcast_phase(ManipulationPhase.FAILED, send_feedback = 0) 00237 #self._grasp_result.manipulation_result.value = ManipulationResult.FAILED 00238 self._grasp_result.manipulation_result.value = ManipulationResult.SUCCESS 00239 #self._as.set_aborted(self._grasp_result) 00240 self._as.set_succeeded(self._grasp_result) 00241 00242 except Preempted: 00243 rospy.loginfo("reactive grasp preempted, returning") 00244 self.rg.broadcast_phase(ManipulationPhase.ABORTED, send_feedback = 0) 00245 self._grasp_result.manipulation_result.value = ManipulationResult.FAILED 00246 self._as.set_preempted(self._grasp_result) 00247 00248 except reactive_grasp.Aborted: 00249 rospy.loginfo("reactive grasp saw a serious error! Aborting") 00250 self.rg.broadcast_phase(ManipulationPhase.ABORTED, send_feedback = 0) 00251 self._grasp_result.manipulation_result.value = ManipulationResult.ERROR 00252 self._as.set_aborted(self._grasp_result) 00253 00254 00255 ##pull relevant parts out of the goal for both reactive grasp and approach 00256 def init_reactive_grasp(self, goal): 00257 00258 self.rg.check_preempt() 00259 00260 self.rg.pressure_listener.set_thresholds() 00261 00262 self.rg.check_preempt() 00263 00264 #check the param server for a new closing force and pass it on 00265 self.close_force = rospy.get_param("~close_force", 100) 00266 self.rg.close_force = self.close_force 00267 rospy.loginfo("using a close_force of %d"%self.close_force) 00268 00269 #pull trajectory angles out of JointTrajectory 00270 if len(goal.trajectory.points) > 0: 00271 trajectory = [goal.trajectory.points[i].positions for i in range(len(goal.trajectory.points))] 00272 print "trajectory:" 00273 for angles in trajectory: 00274 print pplist(angles) 00275 else: 00276 trajectory = None 00277 00278 object_name = "points" 00279 table_name = goal.collision_support_surface_name 00280 00281 #if forward_step is 0, adjust the forward_step depending on whether the grasp is a top or side grasp 00282 #if the palm's x-axis's z-component is high enough, it's a top grasp 00283 if self.forward_step == 0: 00284 forward_step = .06 00285 00286 #transform pose to base_link 00287 bl_pose = change_pose_stamped_frame(self.rg.cm.tf_listener, goal.final_grasp_pose, 'base_link') 00288 palm_mat = pose_to_mat(bl_pose.pose) 00289 if palm_mat[2,0] < -math.cos(math.pi/3): 00290 rospy.loginfo("palm_mat[2,0] = %0.3f, top grasp"%palm_mat[2,0]) 00291 00292 #if it's a top grasp, lower the forward_step 00293 forward_step = .03 00294 else: 00295 rospy.loginfo("side grasp") 00296 else: 00297 forward_step = self.forward_step 00298 00299 self.rg.check_preempt() 00300 00301 return (trajectory, object_name, table_name, forward_step) 00302 00303 00304 ##do a reactive approach using the fingertip sensors 00305 #(backs up and moves to the side if a fingertip contacts on the way to the grasp) 00306 def reactive_approach_cb(self, goal): 00307 00308 rospy.loginfo("got reactive approach request") 00309 try: 00310 self.rg_state = "approach" 00311 (trajectory, object_name, table_name, forward_step) = self.init_reactive_grasp(goal) 00312 00313 #compute the approach dir using the current wrist pose 00314 current_wrist_pose = self.rg.cm.get_current_wrist_pose_stamped() 00315 approach_dir = self.rg.compute_approach_dir(current_wrist_pose, goal.final_grasp_pose) 00316 00317 #perform the reactive approach 00318 self.cm.switch_to_cartesian_mode() 00319 result = self.rg.reactive_approach(approach_dir, goal.final_grasp_pose, trajectory, \ 00320 self.side_step, self.back_step, \ 00321 self.approach_num_tries, self.goal_pos_thres) 00322 self.rg_state = "off" 00323 self.rg.check_preempt() 00324 00325 rospy.loginfo("switching back to joint controllers") 00326 self.cm.switch_to_joint_mode() 00327 00328 if result == 0: 00329 self.rg.broadcast_phase(ManipulationPhase.SUCCEEDED, send_feedback = 0) 00330 self._grasp_result.manipulation_result.value = ManipulationResult.SUCCESS 00331 self._approach_as.set_succeeded(self._grasp_result) 00332 else: 00333 self.rg.broadcast_phase(ManipulationPhase.FAILED, send_feedback = 0) 00334 self._grasp_result.manipulation_result.value = ManipulationResult.FAILED 00335 self._approach_as.set_aborted(self._grasp_result) 00336 00337 except Preempted: 00338 rospy.loginfo("reactive grasp preempted, returning") 00339 self.rg.broadcast_phase(ManipulationPhase.ABORTED, send_feedback = 0) 00340 self._grasp_result.manipulation_result.value = ManipulationResult.FAILED 00341 self._approach_as.set_preempted(self._grasp_result) 00342 00343 except reactive_grasp.Aborted: 00344 rospy.loginfo("reactive grasp saw a serious error! Aborting") 00345 self.rg.broadcast_phase(ManipulationPhase.ABORTED, send_feedback = 0) 00346 self._grasp_result.manipulation_result.value = ManipulationResult.ERROR 00347 self._approach_as.set_aborted(self._grasp_result) 00348 00349 00350 ##do a reactive lift using the fingertip sensors (uses slip-servoing to exert just enough force to grasp and lift) 00351 def reactive_lift_cb(self, goal): 00352 00353 try: 00354 rospy.loginfo("got reactive lift request") 00355 self.cm.switch_to_cartesian_mode() 00356 00357 #lift and check if the object is still within the hand 00358 self.rg_state = "lift" 00359 success = self.rg.lift_carefully(goal.lift, self.min_gripper_opening, self.max_gripper_opening) 00360 00361 #optional shake (used to test the quality of the grasp) 00362 if success and self.shake_object: 00363 00364 #slow shake 00365 success = self.rg.shake_object(None, self.min_gripper_opening, 00366 self.max_gripper_opening, 00367 wrist_roll_shake_time = 1.5, 00368 wrist_flex_shake_time = 1.5, 00369 arm_pan_shake_time = 0.25) 00370 # if success: 00371 00372 # #fast shake 00373 # success = self.rg.shake_object(None, self.min_gripper_opening, 00374 # self.max_gripper_opening, 00375 # wrist_roll_shake_time = 0.5, 00376 # wrist_flex_shake_time = 0.5, 00377 # arm_pan_shake_time = 0.1) 00378 00379 self.rg_state = "off" 00380 00381 rospy.loginfo("switching back to joint controllers") 00382 self.cm.switch_to_joint_mode() 00383 00384 if success: 00385 self.rg.broadcast_phase(ManipulationPhase.SUCCEEDED, send_feedback = 0) 00386 self._lift_result.manipulation_result.value = ManipulationResult.SUCCESS 00387 self._lift_as.set_succeeded(self._lift_result) 00388 else: 00389 self.rg.broadcast_phase(ManipulationPhase.FAILED, send_feedback = 0) 00390 self._lift_result.manipulation_result.value = ManipulationResult.FAILED 00391 self._lift_as.set_aborted(self._lift_result) 00392 00393 except Preempted: 00394 rospy.loginfo("reactive lift preempted, returning") 00395 self.rg.broadcast_phase(ManipulationPhase.ABORTED, send_feedback = 0) 00396 self._lift_result.manipulation_result.value = ManipulationResult.FAILED 00397 self._lift_as.set_preempted(self._lift_result) 00398 00399 except reactive_grasp.Aborted: 00400 rospy.loginfo("reactive lift saw a serious error! Aborting") 00401 self.rg.broadcast_phase(ManipulationPhase.ABORTED, send_feedback = 0) 00402 self._lift_result.manipulation_result.value = ManipulationResult.ERROR 00403 self._lift_as.set_aborted(self._lift_result) 00404 00405 00406 ##do a reactive place using the fingertip sensors and accelerometer 00407 #(uses slip controller to stop and open when the object hits the table) 00408 #if slip controller is not running, just goes past the goal with the Cartesian controller 00409 def reactive_place_cb(self, goal): 00410 00411 try: 00412 rospy.loginfo("got reactive place request") 00413 self.cm.switch_to_cartesian_mode() 00414 00415 #place and open when the object hits the table 00416 self.rg_state = "place" 00417 result = self.rg.place_carefully(goal.final_place_pose, self.place_overshoot, \ 00418 self.min_gripper_opening, self.max_gripper_opening, \ 00419 self.place_angle_max_diff) 00420 00421 self._place_result.manipulation_result.value = ManipulationResult.SUCCESS 00422 if result == 1: 00423 self.rg.broadcast_phase(ManipulationPhase.SUCCEEDED, send_feedback = 0) 00424 self._place_as.set_succeeded(self._place_result) 00425 00426 except Preempted: 00427 rospy.loginfo("reactive place preempted, returning") 00428 self.rg.broadcast_phase(ManipulationPhase.ABORTED, send_feedback = 0) 00429 self._place_result.manipulation_result.value = ManipulationResult.FAILED 00430 self._place_as.set_preempted(self._place_result) 00431 00432 except reactive_grasp.Aborted: 00433 rospy.loginfo("reactive place saw a serious error! Aborting") 00434 self.rg.broadcast_phase(ManipulationPhase.ABORTED, send_feedback = 0) 00435 self._place_result.manipulation_result.value = ManipulationResult.ERROR 00436 self._place_as.set_aborted(self._place_result) 00437 00438 00439 ##do a compliant close using the fingertip sensors (stops at the first detected 00440 #contact and moves the arm so that the contact stays in place) 00441 def compliant_close_callback(self, req): 00442 rospy.loginfo("executing compliant grasp--switching to Cartesian controllers") 00443 self.cm.switch_to_cartesian_mode() 00444 00445 self.rg.compliant_close() 00446 00447 rospy.loginfo("switching back to joint controllers") 00448 self.cm.switch_to_joint_mode() 00449 00450 return EmptyResponse() 00451 00452 00453 ##do a grasp adjustment using the fingertip sensors (tries to move the hand to 00454 #obtain non-tip and non-edge contacts) 00455 def grasp_adjustment_callback(self, req): 00456 rospy.loginfo("executing grasp adjustment--switching to Cartesian controllers") 00457 self.cm.switch_to_cartesian_mode() 00458 00459 #start by opening the hand, restting the fingertips, and doing a compliant close 00460 #to get proper fingertip readings 00461 self.rg.open_and_reset_fingertips() 00462 (initial_l_readings, initial_r_readings) = self.rg.compliant_close() 00463 00464 #get the current gripper pose as the 'desired grasp pose' 00465 current_wrist_pose = self.cm.get_current_wrist_pose_stamped() 00466 00467 #run grasp adjustment 00468 (adjust_result, current_goal_pose) = self.rg.adjust_grasp(current_wrist_pose, \ 00469 initial_l_readings, initial_r_readings, \ 00470 z_step = self.grasp_adjust_z_step, x_step = self.grasp_adjust_x_step, \ 00471 min_gripper_opening = self.min_gripper_opening, \ 00472 max_gripper_opening = self.max_gripper_opening, \ 00473 min_contact_row = self.min_contact_row, 00474 num_tries = self.grasp_adjust_num_tries) 00475 00476 rospy.loginfo("switching back to joint controllers") 00477 self.cm.switch_to_joint_mode() 00478 00479 return EmptyResponse() 00480 00481 00482 if __name__ == "__main__": 00483 00484 if len(sys.argv) < 2 or sys.argv[1] != 'r' and sys.argv[1] != 'l': 00485 rospy.logerr("usage: reactive_grasp_server.py which_arm (which_arm is r or l)") 00486 sys.exit(1) 00487 00488 which_arm = sys.argv[1] 00489 00490 node_name = which_arm+'_reactive_grasp' 00491 rospy.init_node(node_name, anonymous=True) 00492 00493 reactive_grasp_services = ReactiveGraspActionServer(which_arm) 00494 rospy.loginfo("Reactive grasp action ready") 00495 00496 rospy.spin()