door_epc.py
Go to the documentation of this file.
00001 
00002 import numpy as np, math
00003 import copy
00004 from threading import RLock
00005 
00006 import roslib; roslib.load_manifest('hrl_pr2_door_opening')
00007 roslib.load_manifest('equilibrium_point_control')
00008 import rospy
00009 
00010 from equilibrium_point_control.msg import MechanismKinematicsRot
00011 from equilibrium_point_control.msg import MechanismKinematicsJac
00012 from equilibrium_point_control.msg import ForceTrajectory
00013 from geometry_msgs.msg import Point32
00014 from std_msgs.msg import Empty
00015 
00016 import epc
00017 import hrl_lib.util as ut
00018 
00019 class Door_EPC(epc.EPC):
00020     def __init__(self, robot):
00021         epc.EPC.__init__(self, robot)
00022 
00023         self.mech_kinematics_lock = RLock()
00024         self.fit_circle_lock = RLock()
00025 
00026         rospy.Subscriber('mechanism_kinematics_rot',
00027                          MechanismKinematicsRot,
00028                          self.mechanism_kinematics_rot_cb)
00029         rospy.Subscriber('epc/stop', Empty, self.stop_cb)
00030         # used in the ROS stop_cb and equi_pt_generator_control_radial_force
00031         self.force_traj_pub = rospy.Publisher('epc/force_test', ForceTrajectory)
00032         self.mech_traj_pub = rospy.Publisher('mechanism_trajectory', Point32)
00033 
00034     def init_log(self):
00035         self.f_list = []
00036         self.f_list_ati = []
00037         self.f_list_estimate = []
00038         self.f_list_torques = []
00039         self.cep_list = []
00040         self.ee_list = []
00041         self.ft = ForceTrajectory()
00042         if self.mechanism_type != '':
00043             self.ft.type = self.mechanism_type
00044         else:
00045             self.ft.type = 'rotary'
00046 
00047     def log_state(self, arm):
00048         # only logging the right arm.
00049         f = self.robot.get_wrist_force_ati(arm, base_frame=True)
00050         self.f_list_ati.append(f.A1.tolist())
00051 
00052         f = self.robot.get_wrist_force_estimate(arm, base_frame=True)
00053         self.f_list_estimate.append(f.A1.tolist())
00054 
00055         f = self.robot.get_force_from_torques(arm)
00056         self.f_list_torques.append(f.A1.tolist())
00057 
00058         f = self.robot.get_wrist_force(arm, base_frame=True)
00059         self.f_list.append(f.A1.tolist())
00060 
00061         cep, _ = self.robot.get_cep_jtt(arm, hook_tip=True)
00062         self.cep_list.append(cep.A1.tolist())
00063 #        ee, _ = self.robot.get_ee_jtt(arm)
00064         ee, _ = self.robot.end_effector_pos(arm)
00065         self.ee_list.append(ee.A1.tolist())
00066         
00067         if self.started_pulling_on_handle == False:
00068             if f[0,0] > 10.:
00069                 self.started_pulling_on_handle_count += 1
00070             else:
00071                 self.started_pulling_on_handle_count = 0
00072                 self.init_log() # reset logs until started pulling on the handle.
00073                 self.init_tangent_vector = None
00074 
00075             if self.started_pulling_on_handle_count > 1:
00076                 self.started_pulling_on_handle = True
00077 
00078         return ''
00079 
00080     ## ROS callback. Stop and maintain position.
00081     def stop_cb(self, cmd):
00082         self.stopping_string = 'stop_cb called.'
00083 
00084     def common_stopping_conditions(self):
00085         stop = ''
00086         # right arm only.
00087         wrist_force = self.robot.get_wrist_force(0, base_frame=True)
00088         mag = np.linalg.norm(wrist_force)
00089         if mag > self.eq_force_threshold:
00090             stop = 'force exceed'
00091 
00092         if mag < 1.2 and self.hooked_location_moved:
00093             if (self.prev_force_mag - mag) > 30.:
00094                 stop = 'slip: force step decrease and below thresold.'
00095             else:
00096                 self.slip_count += 1
00097         else:
00098             self.slip_count = 0
00099 
00100         if self.slip_count == 10:
00101             stop = 'slip: force below threshold for too long.'
00102         return stop
00103 
00104     def mechanism_kinematics_rot_cb(self, mk):
00105         self.fit_circle_lock.acquire()
00106         self.cx_start = mk.cx
00107         self.cy_start = mk.cy
00108         self.cz_start = mk.cz
00109         self.rad = mk.rad
00110         self.fit_circle_lock.release()
00111 
00112     ## constantly update the estimate of the kinematics and move the
00113     # equilibrium point along the tangent of the estimated arc, and
00114     # try to keep the radial force constant.
00115     # @param h_force_possible - True (hook side) or False (hook up).
00116     # @param v_force_possible - False (hook side) or True (hook up).
00117     # Is maintaining a radial force possible or not (based on hook
00118     # geometry and orientation)
00119     # @param cep_vel - tangential velocity of the cep in m/s
00120     def cep_gen_control_radial_force(self, arm, cep, cep_vel):
00121         self.log_state(arm)
00122         if self.started_pulling_on_handle == False:
00123             cep_vel = 0.02
00124 
00125         #step_size = 0.01 * cep_vel
00126         step_size = 0.1 * cep_vel # 0.1 is the time interval between calls to the equi_generator function (see pull)
00127         stop = self.common_stopping_conditions()
00128         wrist_force = self.robot.get_wrist_force(arm, base_frame=True)
00129         mag = np.linalg.norm(wrist_force)
00130 
00131         curr_pos, _ = self.robot.get_ee_jtt(arm)
00132         if len(self.ee_list)>1:
00133             start_pos = np.matrix(self.ee_list[0]).T
00134         else:
00135             start_pos = curr_pos
00136 
00137         #mechanism kinematics.
00138         if self.started_pulling_on_handle:
00139             self.mech_traj_pub.publish(Point32(curr_pos[0,0],
00140                                        curr_pos[1,0], curr_pos[2,0]))
00141 
00142         self.fit_circle_lock.acquire()
00143         rad = self.rad
00144         cx_start, cy_start = self.cx_start, self.cy_start
00145         cz_start = self.cz_start
00146         self.fit_circle_lock.release()
00147         cx, cy = cx_start, cy_start
00148         cz = cz_start
00149         print 'cx, cy, r:', cx, cy, rad
00150 
00151         radial_vec = curr_pos - np.matrix([cx,cy,cz]).T
00152         radial_vec = radial_vec/np.linalg.norm(radial_vec)
00153         if cy_start < start_pos[1,0]:
00154             tan_x,tan_y = -radial_vec[1,0],radial_vec[0,0]
00155         else:
00156             tan_x,tan_y = radial_vec[1,0],-radial_vec[0,0]
00157         
00158         if tan_x > 0. and (start_pos[0,0]-curr_pos[0,0]) < 0.09:
00159             tan_x = -tan_x
00160             tan_y = -tan_y
00161 
00162         if cy_start > start_pos[1,0]:
00163             radial_vec = -radial_vec # axis to the left, want force in
00164                                    # anti-radial direction.
00165         rv = radial_vec
00166         force_vec = np.matrix([rv[0,0], rv[1,0], 0.]).T
00167         tangential_vec = np.matrix([tan_x, tan_y, 0.]).T
00168         
00169         tangential_vec_ts = tangential_vec
00170         radial_vec_ts = radial_vec
00171         force_vec_ts = force_vec
00172 
00173         if arm == 'right_arm' or arm == 0:
00174             if force_vec_ts[1,0] < 0.: # only allowing force to the left
00175                 force_vec_ts = -force_vec_ts
00176         else:
00177             if force_vec_ts[1,0] > 0.: # only allowing force to the right
00178                 force_vec_ts = -force_vec_ts
00179 
00180         f_vec = -1*np.array([wrist_force[0,0], wrist_force[1,0],
00181                              wrist_force[2,0]])
00182         f_rad_mag = np.dot(f_vec, force_vec.A1)
00183         err = f_rad_mag-4.
00184         if err>0.:
00185             kp = -0.1
00186         else:
00187             kp = -0.2
00188         radial_motion_mag = kp * err # radial_motion_mag in cm (depends on eq_motion step size)
00189         radial_motion_vec =  force_vec * radial_motion_mag
00190         print 'tangential_vec:', tangential_vec.A1
00191         eq_motion_vec = copy.copy(tangential_vec)
00192         eq_motion_vec += radial_motion_vec
00193         
00194         self.prev_force_mag = mag
00195 
00196         if self.init_tangent_vector == None or self.started_pulling_on_handle == False:
00197             self.init_tangent_vector = copy.copy(tangential_vec_ts)
00198         c = np.dot(tangential_vec_ts.A1, self.init_tangent_vector.A1)
00199         ang = np.arccos(c)
00200         if np.isnan(ang):
00201             ang = 0.
00202 
00203         tangential_vec = tangential_vec / np.linalg.norm(tangential_vec) # paranoia abot vectors not being unit vectors.
00204         dist_moved = np.dot((curr_pos - start_pos).A1, tangential_vec_ts.A1)
00205         ftan = abs(np.dot(wrist_force.A1, tangential_vec.A1))
00206         self.ft.tangential_force.append(ftan)
00207         self.ft.radial_force.append(f_rad_mag)
00208 
00209         if self.ft.type == 'rotary':
00210             self.ft.configuration.append(ang)
00211         else: # drawer
00212             print 'dist_moved:', dist_moved
00213             self.ft.configuration.append(dist_moved)
00214 
00215         if self.started_pulling_on_handle:
00216             self.force_traj_pub.publish(self.ft)
00217 
00218 #        if self.started_pulling_on_handle == False:
00219 #            ftan_pull_test = -np.dot(wrist_force.A1, tangential_vec.A1)
00220 #            print 'ftan_pull_test:', ftan_pull_test
00221 #            if ftan_pull_test > 5.:
00222 #                self.started_pulling_on_handle_count += 1
00223 #            else:
00224 #                self.started_pulling_on_handle_count = 0
00225 #                self.init_log() # reset logs until started pulling on the handle.
00226 #                self.init_tangent_vector = None
00227 #
00228 #            if self.started_pulling_on_handle_count > 1:
00229 #                self.started_pulling_on_handle = True
00230 
00231         if abs(dist_moved) > 0.09 and self.hooked_location_moved == False:
00232             # change the force threshold once the hook has started pulling.
00233             self.hooked_location_moved = True
00234             self.eq_force_threshold = ut.bound(mag+30.,20.,80.)
00235             self.ftan_threshold = 1.2 * self.ftan_threshold + 20.
00236         if self.hooked_location_moved:
00237             if abs(tangential_vec_ts[2,0]) < 0.2 and ftan > self.ftan_threshold:
00238                 stop = 'ftan threshold exceed: %f'%ftan
00239         else:
00240             self.ftan_threshold = max(self.ftan_threshold, ftan)
00241 
00242         if self.hooked_location_moved and ang > math.radians(90.):
00243             print 'Angle:', math.degrees(ang)
00244             self.open_ang_exceed_count += 1
00245             if self.open_ang_exceed_count > 2:
00246                 stop = 'opened mechanism through large angle: %.1f'%(math.degrees(ang))
00247         else:
00248             self.open_ang_exceed_count = 0
00249 
00250         cep_t = cep + eq_motion_vec * step_size
00251         cep[0,0] = cep_t[0,0]
00252         cep[1,0] = cep_t[1,0]
00253         cep[2,0] = cep_t[2,0]
00254         
00255         print 'CEP:', cep.A1
00256 
00257         stop = stop + self.stopping_string
00258         return stop, (cep, None)
00259 
00260     def pull(self, arm, force_threshold, cep_vel, mechanism_type=''):
00261         self.mechanism_type = mechanism_type
00262         self.stopping_string = ''
00263         self.eq_pt_not_moving_counter = 0
00264 
00265         self.init_log()
00266 
00267         self.init_tangent_vector = None
00268         self.open_ang_exceed_count = 0.
00269 
00270         self.eq_force_threshold = force_threshold
00271         self.ftan_threshold = 2.
00272         self.hooked_location_moved = False # flag to indicate when the hooking location started moving.
00273         self.prev_force_mag = np.linalg.norm(self.robot.get_wrist_force(arm))
00274         self.slip_count = 0
00275 
00276         self.started_pulling_on_handle = False
00277         self.started_pulling_on_handle_count = 0
00278 
00279         ee_pos, _ = self.robot.get_ee_jtt(arm)
00280 
00281         self.cx_start = ee_pos[0,0]
00282         self.rad = 10.0
00283         self.cy_start = ee_pos[1,0]-self.rad
00284         self.cz_start = ee_pos[2,0]
00285 
00286         cep, _ = self.robot.get_cep_jtt(arm)
00287         arg_list = [arm, cep, cep_vel]
00288         result, _ = self.epc_motion(self.cep_gen_control_radial_force,
00289                                     0.1, arm, arg_list, self.log_state,
00290                                     #0.01, arm, arg_list,
00291                                     control_function = self.robot.set_cep_jtt)
00292 
00293         print 'EPC motion result:', result
00294         print 'Original force threshold:', force_threshold
00295         print 'Adapted force threshold:', self.eq_force_threshold
00296         print 'Adapted ftan threshold:', self.ftan_threshold
00297 
00298         d = {
00299                 'f_list': self.f_list, 'ee_list': self.ee_list,
00300                 'cep_list': self.cep_list, 'ftan_list': self.ft.tangential_force,
00301                 'config_list': self.ft.configuration, 'frad_list': self.ft.radial_force,
00302                 'f_list_ati': self.f_list_ati,
00303                 'f_list_estimate': self.f_list_estimate,
00304                 'f_list_torques': self.f_list_torques
00305             }
00306         ut.save_pickle(d,'pr2_pull_'+ut.formatted_time()+'.pkl')
00307 
00308     def search_and_hook(self, arm, hook_loc, hooking_force_threshold = 5.,
00309                         hit_threshold=15., hit_motions = 1,
00310                         hook_direction = 'left'):
00311         # this needs to be debugged. Hardcoded for now.
00312         #if arm == 'right_arm' or arm == 0:
00313         #    hook_dir = np.matrix([0., 1., 0.]).T # hook direc in home position
00314         #    offset = -0.03
00315         #elif arm == 'left_arm' or arm == 1:
00316         #    hook_dir = np.matrix([0., -1., 0.]).T # hook direc in home position
00317         #    offset = -0.03
00318         #else:
00319         #    raise RuntimeError('Unknown arm: %s', arm)
00320         #start_loc = hook_loc + rot_mat.T * hook_dir * offset
00321 
00322         if hook_direction == 'left':
00323             offset = np.matrix([0., -0.03, 0.]).T
00324             move_dir = np.matrix([0., 1., 0.]).T
00325         elif hook_direction == 'up':
00326             offset = np.matrix([0., 0., -0.03]).T
00327             move_dir = np.matrix([0., 0., 1.]).T
00328         start_loc = hook_loc + offset
00329 
00330         # vector normal to surface and pointing into the surface.
00331         normal_tl = np.matrix([1.0, 0., 0.]).T
00332 
00333         pt1 = start_loc - normal_tl * 0.1
00334         self.robot.go_cep_jtt(arm, pt1)
00335 
00336         raw_input('Hit ENTER to go')
00337 
00338         vec = normal_tl * 0.2
00339         rospy.sleep(1.)
00340         for i in range(hit_motions):
00341             s = self.move_till_hit(arm, vec=vec, force_threshold=hit_threshold, speed=0.07)
00342 
00343         cep_start, _ = self.robot.get_cep_jtt(arm)
00344         cep = copy.copy(cep_start)
00345         arg_list = [arm, move_dir, hooking_force_threshold, cep, cep_start]
00346         print 'Hi there.'
00347         s = self.epc_motion(self.cep_gen_surface_follow, 0.1, arm,
00348                 arg_list, control_function = self.robot.set_cep_jtt)
00349         print 'result:', s
00350         return s
00351 
00352 
00353 if __name__ == '__main__':
00354     import pr2_arms as pa
00355     rospy.init_node('epc_pr2', anonymous = True)
00356     rospy.logout('epc_pr2: ready')
00357 
00358     #pr2_arms = pa.PR2Arms(primary_ft_sensor='ati')
00359     pr2_arms = pa.PR2Arms(primary_ft_sensor='estimate')
00360     door_epc = Door_EPC(pr2_arms)
00361 
00362     r_arm, l_arm = 0, 1
00363     arm = r_arm
00364 
00365     tip = np.matrix([0.35, 0., 0.]).T
00366     pr2_arms.arms.set_tooltip(arm, tip)
00367 
00368     raw_input('Hit ENTER to close')
00369     pr2_arms.close_gripper(arm, effort=80)
00370     raw_input('Hit ENTER to start Door Opening')
00371 
00372     # for cabinets.
00373     #p1 = np.matrix([0.8, -0.40, -0.04]).T # pos 3
00374     #p1 = np.matrix([0.8, -0.10, -0.04]).T # pos 2
00375     p1 = np.matrix([0.8, -0.35, 0.1]).T # pos 1
00376     door_epc.search_and_hook(arm, p1, hook_direction='left')
00377     door_epc.pull(arm, force_threshold=40., cep_vel=0.05)
00378 
00379 #    # hrl toolchest drawer.
00380 #    p1 = np.matrix([0.8, -0.2, -0.17]).T
00381 #    door_epc.search_and_hook(arm, p1, hook_direction='up')
00382 #    door_epc.pull(arm, force_threshold=40., cep_vel=0.05)
00383 
00384 


hrl_pr2_door_opening
Author(s): Advait Jain. Advisor: Prof. Charlie Kemp. Healthcare Robotics Lab, Georgia Tech
autogenerated on Wed Nov 27 2013 12:25:12