00001
00002 import roslib
00003 roslib.load_manifest('pr2_omni_teleop')
00004
00005 import rospy
00006 import tf
00007 import math
00008 import actionlib
00009 import tf.transformations as tr
00010 import numpy as np
00011 import hrl_lib.tf_utils as tfu
00012
00013
00014 from geometry_msgs.msg import PoseStamped
00015 from geometry_msgs.msg import Wrench
00016 from geometry_msgs.msg import Twist
00017 from phantom_omni.msg import PhantomButtonEvent
00018 from teleop_controllers.msg import JTTeleopControllerState
00019 from actionlib_msgs.msg import *
00020 from pr2_controllers_msgs.msg import *
00021 from pr2_msgs.msg import AccelerometerState
00022
00023 import coefficients as coeff
00024
00025 class ForceFeedbackFilter:
00026
00027 def __init__(self, wrench_topic, dest_frame, wrench_frame, force_feedback_topic, kp_name, kd_name):
00028
00029 self.wrench_frame = wrench_frame
00030 self.dest_frame = dest_frame
00031
00032 self.tflistener = tf.TransformListener()
00033
00034 self.omni_fb = rospy.Publisher(force_feedback_topic, Wrench)
00035 self.filtered_fb = rospy.Publisher('/filtered_fb', Wrench)
00036 rospy.Subscriber(wrench_topic, JTTeleopControllerState, self.wrench_callback)
00037
00038 self.enable = False
00039 self.FIR = coeff.coefficients
00040 self.history = np.matrix(np.zeros((3,17)))
00041 self.prev_time = rospy.Time.now().nsecs*1e-9
00042 self.prev_dt = 0.0
00043 self.omni_max_limit = np.array([5., 5., 5.])
00044 self.omni_min_limit = np.array([-5., -5., -5.])
00045 self.kp = rospy.get_param(kp_name)
00046 self.kd = rospy.get_param(kd_name)
00047 self.force_scaling = 0.025
00048 self.force_old = np.zeros(3)
00049
00050 def set_force_scaling(self, force):
00051 self.force_scaling = force
00052
00053 def set_enable(self, v):
00054 self.enable = v
00055
00056 def wrench_callback(self, state):
00057 x_err = np.matrix([state.x_err.linear.x, state.x_err.linear.y, state.x_err.linear.z]).T
00058 x_dot = np.matrix([state.xd.linear.x, state.xd.linear.y, state.xd.linear.z]).T
00059 feedback = -1.0*self.kp*x_err-self.kd*x_dot
00060 wr_ee = [state.F.force.x, state.F.force.y, state.F.force.z]
00061
00062 shift_right = np.array(self.history[:,0:self.FIR.size-1])
00063 new_col = np.array(wr_ee).reshape((3,1))
00064 self.history = np.matrix(np.hstack((new_col, shift_right)))
00065 wr_ee_filt = self.history*self.FIR
00066 df_R_ee = tfu.rotate(self.dest_frame, 'torso_lift_link', self.tflistener) * \
00067 tfu.rotate('torso_lift_link', self.wrench_frame, self.tflistener)
00068 wr_df = self.force_scaling*np.array(tr.translation_from_matrix(df_R_ee * tfu.translation_matrix([wr_ee_filt[0,0], wr_ee_filt[1,0], wr_ee_filt[2,0]])))
00069 wr_df = np.where(wr_df>self.omni_max_limit, self.omni_max_limit, wr_df)
00070 wr_df = np.where(wr_df<self.omni_min_limit, self.omni_min_limit, wr_df)
00071
00072
00073
00074
00075
00076
00077
00078 wr = Wrench()
00079
00080 wr.force.x = -wr_df[0]
00081 wr.force.y = -wr_df[1]
00082 wr.force.z = -wr_df[2]
00083
00084 test = Wrench()
00085 test.force.x = feedback[0,0]
00086 test.force.y = feedback[1,0]
00087 test.force.z = feedback[2,0]
00088
00089 self.force_old[0] = wr.force.x
00090 self.force_old[1] = wr.force.y
00091 self.force_old[2] = wr.force.z
00092
00093
00094 self.filtered_fb.publish(test)
00095 if self.enable == True:
00096 self.omni_fb.publish(wr)
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116 def limit_range(numb, lower, upper):
00117 if lower > upper:
00118 raise RuntimeError('lower bound > upper bound, wa?')
00119 return max(min(numb, upper), lower)
00120
00121 class GripperOmniHandler:
00122 def __init__(self, topic, controller):
00123 rospy.Subscriber(topic, PhantomButtonEvent, self.button_event)
00124 self.gripper_server = actionlib.SimpleActionClient(controller + '/gripper_action', Pr2GripperCommandAction)
00125 self.gripper_server.wait_for_server()
00126 self.gripper_pose = None
00127 self.gripper_open = False
00128 self.gripper_close = False
00129 self.MAX_EFFORT = 40
00130 self.enabled = True
00131
00132 def set_enabled(self, v):
00133 self.enabled = v
00134
00135 def button_event(self, msg):
00136 if not (msg.grey_button == 1 and msg.white_button == 1):
00137
00138 if msg.grey_button == 1:
00139 if self.enabled:
00140 self.gripper_server.send_goal(Pr2GripperCommandGoal(
00141 Pr2GripperCommand(position = 0.0, max_effort = self.MAX_EFFORT)),
00142 done_cb = self.gripper_done_cb,
00143 feedback_cb=self.gripper_fb_cb)
00144 self.gripper_close = True
00145 elif msg.grey_button == 0 and self.gripper_pose != None and self.gripper_close:
00146 self.gripper_server.send_goal(Pr2GripperCommandGoal(
00147 Pr2GripperCommand(position = self.gripper_pose-.01, max_effort = self.MAX_EFFORT))
00148 )
00149 self.gripper_close = False
00150 self.gripper_pose = None
00151
00152
00153 if msg.white_button == 1:
00154 if self.enabled:
00155 self.gripper_server.send_goal(Pr2GripperCommandGoal(
00156 Pr2GripperCommand(position = 0.09, max_effort = self.MAX_EFFORT)),
00157 done_cb = self.gripper_done_cb,
00158 feedback_cb=self.gripper_fb_cb)
00159 self.l_gripper_open = True
00160 elif msg.white_button == 0 and self.gripper_pose != None and self.gripper_open:
00161 self.gripper_server.send_goal(Pr2GripperCommandGoal(
00162 Pr2GripperCommand(position = self.gripper_pose+.01, max_effort = self.MAX_EFFORT)))
00163 self.l_gripper_open = False
00164 self.gripper_pose = None
00165
00166 def gripper_done_cb(self, state, msg):
00167 self.gripper_pose = msg.position
00168
00169 def gripper_fb_cb(self, msg):
00170 self.gripper_pose = msg.position
00171 self.effort = msg.effort
00172
00173 class AccelerometerFeedback:
00174
00175 def __init__(self, dest_frame, accel_topic, force_topic, tflistener):
00176 rospy.Subscriber(accel_topic, AccelerometerState, self.cb)
00177 self.viz_pub = rospy.Publisher('omni1_force', PoseStamped)
00178 self.tflistener = tflistener
00179 self.dest_frame = dest_frame
00180 self.force_pub = rospy.Publisher(force_topic, Wrench)
00181 self.gain = .5
00182
00183 def cb(self, msg):
00184 raw_read = [msg.samples[0].x, msg.samples[0].y, msg.samples[0].z]
00185 g = tr.translation_from_matrix(
00186 tfu.rotate(msg.header.frame_id, 'base_footprint', self.tflistener) * \
00187 tr.translation_matrix([0, 0, 9.665]))
00188 grav_adjusted = np.array(raw_read) - np.array(g)
00189
00190
00191 d_R_m = tfu.rotate(self.dest_frame, 'torso_lift_link', self.tflistener) * \
00192 tfu.rotate('torso_lift_link', msg.header.frame_id, self.tflistener)
00193
00194 t_sensable = self.gain * np.array(tr.translation_from_matrix(d_R_m * np.matrix(tr.translation_matrix(grav_adjusted))))
00195 w = Wrench()
00196 w.force.x = t_sensable[0]
00197 w.force.y = t_sensable[1]
00198 w.force.z = t_sensable[2]
00199 self.force_pub.publish(w)
00200
00201 ps = PoseStamped()
00202 ps.header.frame_id = self.dest_frame
00203 ps.header.stamp = rospy.get_rostime()
00204 ps.pose.position.x = t_sensable[0]
00205 ps.pose.position.y = t_sensable[1]
00206 ps.pose.position.z = t_sensable[2]
00207 ps.pose.orientation.w = 1
00208 self.viz_pub.publish(ps)
00209
00210 class JTWrenchFeedback:
00211 def __init__(self,
00212 wrench_topic,
00213 wrench_frame,
00214 dest_frame,
00215 force_feedback_topic,
00216 tflistener):
00217 self.wrench_frame = wrench_frame
00218 self.dest_frame = dest_frame
00219 self.tflistener = tflistener
00220
00221 self.omni_fb = rospy.Publisher(force_feedback_topic, Wrench)
00222 self.filtered_fb = rospy.Publisher('/filtered_fb', Wrench)
00223 rospy.Subscriber(wrench_topic, Twist, self.wrench_callback)
00224 self.enable = False
00225 self.history = np.zeros((3,4))
00226 self.prev_time = rospy.Time.now().nsecs*1e-9
00227 self.prev_dt = 0.0
00228
00229 def set_enable(self, v):
00230 self.enable = v
00231
00232 def wrench_callback(self, w):
00233 wr_tool = [w.linear.x, w.linear.y, w.linear.z]
00234 df_R_wf = tfu.rotate(self.dest_frame, 'torso_lift_link', self.tflistener) * \
00235 tfu.rotate('torso_lift_link', self.wrench_frame, self.tflistener)
00236 wr_df = np.array(tr.translation_from_matrix(df_R_wf * tfu.translation_matrix(wr_tool)))
00237
00238
00239 wr_sensable = 0.2*wr_df+0.2*self.history[:,0]+0.2*self.history[:,1]+0.2*self.history[:,2]+0.2*self.history[:,3]
00240 self.history[:,1:] = self.history[:,0:3]
00241 self.history[:,0] = wr_sensable
00242 wr = Wrench()
00243 wr.force.x = wr_sensable[0]
00244 wr.force.y = wr_sensable[1]
00245 wr.force.z = wr_sensable[2]
00246 self.filtered_fb.publish(wr)
00247
00248 dt = rospy.Time.now().nsecs*1e-9-self.prev_time
00249 self.prev_time = rospy.Time.now().nsecs*1e-9
00250
00251 print "time_Step in force :", dt
00252
00253 if self.enable:
00254 wr = Wrench()
00255 wr.force.x = wr_sensable[0]
00256 wr.force.y = wr_sensable[1]
00257 wr.force.z = wr_sensable[2]
00258
00259
00260
00261
00262
00263 class ControlPR2Arm:
00264
00265 def __init__(self, omni_name,
00266 pr2_control_topic,
00267 gripper_control_topic,
00268 gripper_tip_frame,
00269 center_in_torso_frame,
00270 scaling_in_base_frame,
00271 tfbroadcast,
00272 tflistener):
00273
00274
00275 self.enabled = False
00276 self.zero_out_forces = True
00277
00278 self.X_BOUNDS = [.3, 1.5]
00279 self.kPos = 15.
00280 self.kVel = 0.5
00281 self.kPos_close = 70.
00282 self.omni_name = omni_name
00283 self.center_in_torso_frame = center_in_torso_frame
00284 self.scaling_in_base_frame = scaling_in_base_frame
00285 self.tflistener = tflistener
00286 self.tfbroadcast = tfbroadcast
00287 self.gripper_tip_frame = gripper_tip_frame
00288 self.prev_time = rospy.Time.now().nsecs*1e-9
00289 self.prev_dt = 0.0
00290
00291 rate = rospy.Rate(100.0)
00292
00293
00294
00295
00296 rospy.loginfo('Attempting to link ' + omni_name + ' to the PR2\'s torso frame.')
00297 success = False
00298 while not success and (not rospy.is_shutdown()):
00299 self.send_transform_to_link_omni_and_pr2_frame()
00300 rate.sleep()
00301 try:
00302 self.scale_omni_l0 = np.abs(self.l0_rotate_base(self.scaling_in_base_frame))
00303 success = True
00304 except tf.LookupException, e:
00305 pass
00306
00307 except tf.ConnectivityException, e:
00308 pass
00309
00310 rospy.loginfo('Finished linking frame for %s' % omni_name)
00311
00312 self.omni_fb = rospy.Publisher(self.omni_name + '_force_feedback', Wrench)
00313 self.pr2_pub = rospy.Publisher(pr2_control_topic, PoseStamped)
00314
00315 self.scale_omni_l0 = np.abs(self.l0_rotate_base(self.scaling_in_base_frame))
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327 rospy.Subscriber(self.omni_name + '_pose', PoseStamped, self.omni_pose_cb)
00328 self.gripper_handler = GripperOmniHandler(self.omni_name + '_button', gripper_control_topic)
00329
00330
00331
00332 def send_transform_to_link_omni_and_pr2_frame(self):
00333 self.tfbroadcast.sendTransform(self.center_in_torso_frame,
00334 tuple(tf.transformations.quaternion_from_euler(0, 0, 0)),
00335 rospy.Time.now(),
00336 self.omni_name,
00337 "/torso_lift_link")
00338
00339
00340
00341
00342
00343
00344
00345
00346 def l0_rotate_base(self, vec_base):
00347 m = tfu.translation_matrix(vec_base)
00348 vec_l0 = tr.translation_from_matrix((tfu.rotate('/base_footprint', '/torso_lift_link', self.tflistener) * \
00349 tfu.rotate('/torso_lift_link', self.omni_name + '_link0', self.tflistener)).T * m)
00350 return np.array(vec_l0)
00351
00352
00353
00354 def torso_T_omni(self, omni_tip, msg_frame):
00355
00356
00357 z_T_6 = tfu.transform(self.omni_name + '_link0', msg_frame, self.tflistener)
00358 tip_0 = z_T_6 * omni_tip
00359 tip_0t = (np.array(tr.translation_from_matrix(tip_0)) * np.array(self.scale_omni_l0)).tolist()
00360 tip_0q = tr.quaternion_from_matrix(tip_0)
00361
00362
00363 tll_T_0 = tfu.transform('/torso_lift_link', self.omni_name + '_link0', self.tflistener)
00364 tip_torso_mat = tll_T_0 * tfu.tf_as_matrix([tip_0t, tip_0q])
00365 tip_tt, tip_tq = tfu.matrix_as_tf(tip_torso_mat)
00366 tip_tt[0] = limit_range(tip_tt[0], self.X_BOUNDS[0], self.X_BOUNDS[1])
00367 return tip_tt, tip_tq
00368
00369
00370
00371 def omni_T_torso(self, torso_mat):
00372 l0_mat = tfu.transform(self.omni_name + '_link0', '/torso_lift_link', self.tflistener) * torso_mat
00373 l0_t = (np.array(tr.translation_from_matrix(l0_mat)) / np.array(self.scale_omni_l0)).tolist()
00374 l0_q = tr.quaternion_from_matrix(l0_mat)
00375 omni_pt_mat = tfu.transform(self.omni_name, self.omni_name + '_link0', self.tflistener) * tfu.tf_as_matrix((l0_t, l0_q))
00376 return tfu.matrix_as_tf(omni_pt_mat)
00377
00378
00379
00380
00381 def set_control(self, s):
00382 self.enabled = s
00383 if self.enabled:
00384 self.gripper_handler.set_enabled(True)
00385 self.zero_out_forces = True
00386 else:
00387 self.gripper_handler.set_enabled(False)
00388
00389
00390
00391 def omni_pose_cb(self, msg):
00392 if self.enabled:
00393
00394 tip_omni, msg_frame = tfu.posestamped_as_matrix(msg)
00395 tip_tt, tip_tq = self.torso_T_omni(tip_omni, msg_frame)
00396
00397
00398 ps = PoseStamped()
00399 ps.header.frame_id = '/torso_lift_link'
00400 ps.header.stamp = rospy.get_rostime()
00401 ps.pose.position.x = tip_tt[0]
00402 ps.pose.position.y = tip_tt[1]
00403 ps.pose.position.z = tip_tt[2]
00404 ps.pose.orientation.x = tip_tq[0]
00405 ps.pose.orientation.y = tip_tq[1]
00406 ps.pose.orientation.z = tip_tq[2]
00407 ps.pose.orientation.w = tip_tq[3]
00408 self.pr2_pub.publish(ps)
00409 if self.zero_out_forces:
00410 wr = Wrench()
00411 wr.force.x = 0
00412 wr.force.y = 0
00413 wr.force.z = 0
00414 self.omni_fb.publish(wr)
00415 self.zero_out_forces = False
00416 else:
00417 tip_omni, msg_frame = tfu.posestamped_as_matrix(msg)
00418 m_o1 = tfu.transform(self.omni_name, msg_frame, self.tflistener) * tip_omni
00419 ee_point = np.matrix(tr.translation_from_matrix(m_o1)).T
00420
00421
00422 tip_torso = tfu.transform('/torso_lift_link', self.gripper_tip_frame, self.tflistener) \
00423 * tfu.tf_as_matrix(([0.,0.,0.], tr.quaternion_from_euler(0,0,0)))
00424 center_t, center_q = self.omni_T_torso(tip_torso)
00425 center_col_vec = np.matrix(center_t).T
00426
00427
00428 tip_tt, tip_tq = self.torso_T_omni(tfu.tf_as_matrix((center_t, center_q)), self.omni_name)
00429 ps = PoseStamped()
00430 ps.header.frame_id = '/torso_lift_link'
00431 ps.header.stamp = rospy.get_rostime()
00432 ps.pose.position.x = tip_tt[0]
00433 ps.pose.position.y = tip_tt[1]
00434 ps.pose.position.z = tip_tt[2]
00435 ps.pose.orientation.x = tip_tq[0]
00436 ps.pose.orientation.y = tip_tq[1]
00437 ps.pose.orientation.z = tip_tq[2]
00438 ps.pose.orientation.w = tip_tq[3]
00439 self.pr2_pub.publish(ps)
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450 dt = rospy.Time.now().nsecs*1e-9-self.prev_time
00451 self.prev_time = rospy.Time.now().nsecs*1e-9
00452 if dt>0:
00453 self.prev_dt = dt
00454 err_dir = center_col_vec - ee_point
00455 if np.linalg.norm(err_dir) < .15:
00456 force_o1 = self.kPos*err_dir
00457 else:
00458 force_o1 = 0.*err_dir
00459
00460
00461
00462 force_s = tfu.transform(self.omni_name + '_sensable', self.omni_name, self.tflistener) * np.row_stack((force_o1, np.matrix([1.])))
00463 wr = Wrench()
00464 wr.force.x = force_s[0]
00465 wr.force.y = force_s[1]
00466 wr.force.z = force_s[2]
00467 self.omni_fb.publish(wr)
00468
00469
00470 class OmniPR2Teleop:
00471 def __init__(self):
00472 rospy.init_node('omni_frames')
00473 self.enabled = False
00474 self.tfbroadcast = tf.TransformBroadcaster()
00475 self.tflistener = tf.TransformListener()
00476
00477 self.left_controller = ControlPR2Arm(
00478 omni_name ='omni1',
00479 pr2_control_topic = 'l_cart/command_pose',
00480 gripper_control_topic = 'l_gripper_controller',
00481 gripper_tip_frame = 'l_gripper_tool_frame',
00482 center_in_torso_frame = [1.2, .3, -1],
00483 scaling_in_base_frame = [3.5, 3., 5.],
00484 tfbroadcast=self.tfbroadcast,
00485 tflistener=self.tflistener)
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501 self.left_feedback = ForceFeedbackFilter(wrench_topic = '/l_cart/state',
00502 dest_frame = '/omni1_sensable',
00503 wrench_frame = '/l_gripper_tool_frame',
00504 force_feedback_topic = 'omni1_force_feedback',
00505 kp_name = '/l_cart/cart_gains/trans/p',
00506 kd_name = '/l_cart/cart_gains/trans/d')
00507
00508
00509
00510
00511 rospy.Subscriber('omni1_button', PhantomButtonEvent, self.omni_safety_lock_cb)
00512 rospy.Subscriber('omni2_button', PhantomButtonEvent, self.omni_safety_lock_cb)
00513 self.set_state(False)
00514
00515 def omni_safety_lock_cb(self, msg):
00516 if msg.grey_button == 1 and msg.white_button == 1:
00517 self.set_state(not self.enabled)
00518
00519 def set_state(self, s):
00520 self.enabled = s
00521 if self.enabled:
00522 rospy.loginfo('control ENABLED.')
00523 self.left_controller.set_control(True)
00524 self.left_feedback.set_enable(True)
00525
00526 else:
00527 rospy.loginfo('control disabled. Follow potential well to pose of arm.')
00528 self.left_controller.set_control(False)
00529 self.left_feedback.set_enable(False)
00530
00531
00532 def run(self):
00533 rate = rospy.Rate(100.0)
00534 rospy.loginfo('running...')
00535 while not rospy.is_shutdown():
00536 self.left_controller.send_transform_to_link_omni_and_pr2_frame()
00537
00538 rate.sleep()
00539
00540
00541 if __name__ == '__main__':
00542
00543
00544 o = OmniPR2Teleop()
00545 o.run()
00546
00547
00548
00549