$search
00001 #!/usr/bin/env python 00002 # 00003 # Copyright (c) 2010, Bosch LLC 00004 # All rights reserved. 00005 # 00006 # Redistribution and use in source and binary forms, with or without 00007 # modification, are permitted provided that the following conditions are met: 00008 # 00009 # * Redistributions of source code must retain the above copyright 00010 # notice, this list of conditions and the following disclaimer. 00011 # * Redistributions in binary form must reproduce the above copyright 00012 # notice, this list of conditions and the following disclaimer in the 00013 # documentation and/or other materials provided with the distribution. 00014 # * Neither the name of Bosch LLC nor the names of its 00015 # contributors may be used to endorse or promote products derived from 00016 # this software without specific prior written permission. 00017 # 00018 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 00019 # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00020 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00021 # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 00022 # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 00023 # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 00024 # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00025 # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 00026 # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 00027 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00028 # POSSIBILITY OF SUCH DAMAGE. 00029 # 00030 # Authors: Christian Bersch, Bosch LLC 00031 # 00032 00033 00034 00035 00036 import roslib; roslib.load_manifest("pr2_dremel_server") 00037 import actionlib 00038 import rospy 00039 import copy 00040 import pr2_controllers_msgs.msg 00041 from pr2_controller_manager import pr2_controller_manager_interface 00042 00043 import geometry_msgs.msg 00044 import kinematics_msgs.msg 00045 import kinematics_msgs.srv 00046 import arm_navigation_msgs.msg 00047 import arm_navigation_msgs.srv 00048 import trajectory_msgs.msg 00049 from std_msgs.msg import * 00050 from sensor_msgs.msg import * 00051 from math import * 00052 import numpy as np 00053 import tf 00054 import tf.listener 00055 import threading 00056 from simple_robot_control.srv import ReturnJointStates 00057 00058 00059 from controller_interface import * 00060 00061 import simple_robot_control 00062 import numpy 00063 00064 import pr2_dremel_server.msg as action_msg 00065 00066 00067 00068 00069 force = 3.0 00070 #quats_default = (0.009, -0.022, 0.018, 1.000) 00071 00072 #This are the parameters for the table top plane position and orientation. 00073 #These can be retrieved by placing the dremel tool parallel to and slightly above the work piece. 00074 #Run rosrun tf tf_echo /torso_lift_link /r_gripper_tool_frame for obtaining these values 00075 00076 00077 quats_default = ( 0.003, -0.017, -0.018, 1.000) 00078 table_height_default = -0.245 00079 00080 00081 table_height = table_height_default 00082 quats = quats_default 00083 00084 00085 def scale_pts(points): 00086 min_x = min(points[:,0]) 00087 max_x = max(points[:,0]) 00088 00089 min_y = min(points[:,1]) 00090 max_y = max(points[:,1]) 00091 print "max_y", max_y 00092 print "min_y", min_y 00093 points[:,0] -= 0.5 * (max_x + min_x) 00094 points[:,1] -= 0.5 * (max_y + min_y) 00095 pts_temp = copy.deepcopy(points[:,1]) 00096 points[:,1] = points[:,0] 00097 points[:,0] = pts_temp 00098 points[:,0] *= -1.0 00099 points[:,1] *= -1.0 00100 print "zeroed pts", points 00101 scale_factor = 0.08 / (max_y - min_y) 00102 points[:,0] *= scale_factor 00103 points[:,1] *= scale_factor 00104 00105 points[:,0] += 0.55 00106 00107 return points 00108 00109 00110 00111 max_vel = 0.002 00112 00113 00114 class DremelPlotter: 00115 def __init__(self): 00116 rospy.set_param("r_arm_subset_controller", rospy.get_param("r_arm_controller")) 00117 rospy.set_param("r_arm_subset_controller/joints", r_arm_joints_without_shoulder) 00118 00119 quats = rospy.get_param("~gripper_orientation", quats_default) 00120 table_height = rospy.get_param("~table_torso_z", table_height_default) 00121 print "table_height", table_height 00122 print 'orienta', quats 00123 # rospy.set_param 00124 00125 self.shoulder_controller = JointForceController("r_shoulder_lift_joint") 00126 self.arm_position = ArmPositionController("r_arm_controller") 00127 self.arm_subset_position = ArmPositionController("r_arm_subset_controller") 00128 00129 self.arm_subset_position.load() 00130 00131 00132 00133 self.arm = Arm("/r_arm_controller", "/pr2_right_arm_kinematics") 00134 # self.arm_subset = Arm("/r_arm_subset_controller", "/pr2_right_arm_kinematics") 00135 00136 self.listener = tf.TransformListener() 00137 00138 self.force_thresh = 0 00139 self.current_table_z = 0.0 00140 self.reposition_offset_x = 0.002 00141 00142 00143 00144 00145 00146 #actionserver stuff 00147 self._feedback = action_msg.CarveSegmentsFeedback() 00148 self._result = action_msg.CarveSegmentsResult() 00149 self._as = None 00150 00151 def startActionServer(self): 00152 self._as = actionlib.SimpleActionServer("dremel_actionserver", action_msg.CarveSegmentsAction, execute_cb=self.plot_CB, auto_start = False) 00153 self._as.start() 00154 00155 00156 def joint_states_callback(self, msg): 00157 # print 'in js callback msg:' 00158 self.lock.acquire() 00159 self.name = msg.name 00160 self.position = msg.position 00161 self.velocity = msg.velocity 00162 self.effort = msg.effort 00163 self.lock.release() 00164 rospy.sleep(0.01) 00165 00166 #thread function: listen for joint_states messages 00167 def joint_states_listener(self): 00168 rospy.Subscriber('joint_states', JointState, self.joint_states_callback) 00169 rospy.spin() 00170 00171 def getJointEfforts(self): 00172 efforts = [] 00173 self.lock.acquire() 00174 all_name = self.name[:] 00175 all_effort = self.effort[:] 00176 self.lock.release() 00177 for cur_name in self.arm.joint_names: 00178 if cur_name in all_name: 00179 index = all_name.index(cur_name) 00180 efforts.append(all_effort[index]) 00181 print 'efforts : ', efforts 00182 return efforts 00183 00184 def getJointEffortsNT(self): 00185 msg = rospy.wait_for_message("joint_states", JointState) 00186 efforts = [] 00187 for cur_name in self.arm.joint_names: 00188 if cur_name in msg.name: 00189 index = msg.name.index(cur_name) 00190 efforts.append(msg.effort[index]) 00191 print 'efforts : ', efforts 00192 return efforts 00193 00194 00195 def approach(self, point): #postion to force 00196 self.shoulder_controller.stop() 00197 self.arm_subset_position.stop() 00198 self.arm_position.start() 00199 (trans_l,rot_l) = self.listener.lookupTransform( 'torso_lift_link', 'r_wrist_roll_link', rospy.Time(0)) 00200 print "current pos", trans_l[0], trans_l[1], trans_l[2] 00201 print "approach point", point[0], point[1], point[2] 00202 00203 hit_wood = False 00204 pos = point[:] 00205 num_steps = 0 00206 while not hit_wood: 00207 current_efforts = self.getJointEffortsNT() 00208 if current_efforts[1] > 0.0: 00209 print "hit wood!" 00210 hit_wood = True 00211 pos[2] = (num_steps + 1) * -0.002 + trans_l[2] 00212 self.arm.goToPose(pos, quats, "torso_lift_link",0.5) 00213 self.current_table_z = pos[2] 00214 00215 else: 00216 num_steps = num_steps + 1 00217 pos = point[:] 00218 pos[2] = num_steps * -0.002 + trans_l[2] 00219 self.arm.goToPose(pos, quats, "torso_lift_link",0.5) 00220 00221 00222 self.arm_position.stop() 00223 self.shoulder_controller.start() 00224 self.arm_subset_position.start() 00225 rospy.sleep(1) 00226 print "approach done and in force control" 00227 00228 00229 00230 00231 00232 def reposition(self, point): #force to position 00233 print "repostion" 00234 (trans_l,rot_l) = self.listener.lookupTransform( 'torso_lift_link', 'r_wrist_roll_link', rospy.Time(0)) 00235 self.arm_subset_position.stop() 00236 self.shoulder_controller.stop() 00237 self.arm_position.start() 00238 trans_l = list(trans_l) 00239 trans_l[0] += self.reposition_offset_x 00240 trans_l[2] += 0.004 00241 self.arm.goToPose(trans_l, quats, "torso_lift_link",0.5) 00242 point[0] += self.reposition_offset_x 00243 self.arm.goToPose(point, quats, "torso_lift_link", 2) 00244 print 'reposition done' 00245 00246 00247 00248 def plot_CB(self, goal): 00249 approach_offset = 0.025 00250 00251 print "goal", goal 00252 self.num_segments = len(goal.segments) 00253 self.segs_completed = 0 00254 pts = [] 00255 for seg in goal.segments: 00256 if self.num_segments > 0: 00257 first_point = [seg.points[0].x,seg.points[0].y, approach_offset] 00258 pts.append(first_point) 00259 for p in seg.points[:-1]: 00260 point = [p.x, p.y, 0.0] 00261 pts.append(point) 00262 if self.num_segments > 1: 00263 last_point = [seg.points[-2].x,seg.points[-2].y, approach_offset] 00264 pts.append(last_point) 00265 00266 points = numpy.array(pts) 00267 points[:,2] += table_height 00268 00269 print "points", points 00270 00271 points = scale_pts(points) 00272 print "points", points 00273 00274 00275 00276 self.shoulder_controller.stop() 00277 self.arm_subset_position.stop() 00278 self.arm_position.start() 00279 00280 00281 approach_z = points[0][2] 00282 print "approach_z", approach_z 00283 00284 #go to first point 00285 first_point = points[0] 00286 prev = first_point[:] 00287 first_point[2] +=0.03 00288 first_pose = makePose(first_point, quats, "torso_lift_link") 00289 current_angles = self.arm.getArmSeedAngles() 00290 ik = self.arm.getIK(first_pose, "r_wrist_roll_link", current_angles) 00291 self.arm.goToAngle(ik.solution.joint_state.position, 3.0) 00292 00293 force_control = False 00294 last_command = None 00295 success = True 00296 00297 for p in points: 00298 if self._as.is_preempt_requested(): 00299 rospy.loginfo('Preempted') 00300 self._as.set_preempted() 00301 success = False 00302 break 00303 print "at point", p[0],p[1],p[2] 00304 print "table_z", self.current_table_z 00305 if p[2] < approach_z: 00306 force_control = True 00307 p[2] = self.current_table_z 00308 else: 00309 force_control = False 00310 00311 dist = numpy.linalg.norm(prev - p) 00312 max_time = 0.1 + dist / max_vel 00313 max_time = min(max_time, 10.0) 00314 rospy.loginfo("%f %f", dist, max_time) 00315 pose = makePose(p, quats , "torso_lift_link") 00316 current_angles = self.arm.getArmSeedAngles() 00317 ik = self.arm.getIK(pose, "r_wrist_roll_link", current_angles) 00318 subset_joints = self.arm_subset.getJointNames() 00319 angles = [] 00320 for joint in subset_joints: 00321 angles.append(ik.solution.joint_state.position[ ik.solution.joint_state.name.index(joint) ] ) 00322 00323 00324 00325 shoulder_position = ik.solution.joint_state.position[ ik.solution.joint_state.name.index("r_shoulder_lift_joint") ] 00326 00327 if force_control != last_command: 00328 if force_control: # approaching, so we move elbow last from position control to froce control 00329 print 'approaching' 00330 self.approach(p) 00331 print 'force elbow' 00332 self.shoulder_controller.force(force) 00333 print 'force elbow done' 00334 rospy.sleep(1) 00335 else: # pulling away, so we move elbow first - from force control to position control 00336 print 'pulling away and position to', p 00337 self.reposition(p) 00338 self.segs_completed = self.segs_completed + 1 00339 self._feedback.percent_complete = (float) (self.segs_completed) / self.num_segments 00340 self._as.publish_feedback(self._feedback) 00341 rospy.sleep(2) 00342 00343 else: # just go to the next position 00344 if not force_control: #staying in position control 00345 print 'repositioning to point', p 00346 self.arm.goToPose(p, quats, "torso_lift_link",2.0) 00347 00348 else: 00349 print 'force drawing to angles', angles 00350 self.arm_subset.goToAngle(angles, max_time) #staying in froce control 00351 print 'force drawing done' 00352 00353 last_command = force_control 00354 prev = p 00355 00356 rospy.sleep(2) 00357 self.shoulder_controller.stop() 00358 self.arm_subset_position.stop() 00359 self.arm_position.start() 00360 00361 00362 prev[2] +=0.05 00363 last_pose = makePose(prev, quats, "torso_lift_link") 00364 ik = self.arm.getIK(last_pose, "r_wrist_roll_link", self.arm.getArmSeedAngles()) 00365 self.arm.goToAngle(ik.solution.joint_state.position, 3.0) 00366 00367 if success: 00368 self._as.set_succeeded(self._result) 00369 00370 00371 00372 00373 if __name__ == '__main__': 00374 try: 00375 # Initializes a rospy node so that the SimpleActionClient can 00376 # publish and subscribe over ROS. 00377 rospy.init_node('dremel_plotter_actionserver') 00378 00379 dremel = DremelPlotter() 00380 dremel.startActionServer() 00381 rospy.spin() 00382 00383 except rospy.ROSInterruptException: 00384 print "program interrupted before completion"