00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 import math
00028 import numpy as np
00029 import threading
00030 import itertools as it
00031 import sys, signal
00032
00033 import roslib
00034 roslib.load_manifest("hrl_haptic_mpc")
00035 import rospy
00036 import geometry_msgs.msg as geom_msgs
00037 from tf import TransformListener
00038 from std_msgs.msg import Header
00039
00040 from hrl_lib import transforms as tr
00041 import hrl_haptic_manipulation_in_clutter_msgs.msg as haptic_msgs
00042 import multiarray_to_matrix
00043 import haptic_mpc_util
00044 import skin_client as sc
00045
00046
00047 class RobotHapticStateServer():
00048
00049 def __init__(self, opt, node_name=None):
00050 self.opt = opt
00051
00052 self.node_name = node_name
00053 self.tf_listener = None
00054 self.state_pub = None
00055 self.rate = 100.0
00056 self.msg_seq = 0
00057
00058
00059 self.base_path = "/haptic_mpc"
00060
00061
00062 self.skin_topic_list = []
00063 self.skin_client = None
00064
00065
00066 self.robot = None
00067
00068
00069 self.joint_names = []
00070 self.joint_angles = []
00071 self.desired_joint_angles = []
00072 self.joint_velocities = []
00073 self.joint_stiffness = []
00074 self.joint_damping = []
00075 self.joint_data_lock = threading.RLock()
00076 self.joint_names = []
00077
00078
00079 self.end_effector_position = None
00080 self.end_effector_orient_cart = None
00081 self.end_effector_orient_quat = None
00082
00083 self.torso_pose = geom_msgs.Pose()
00084
00085
00086 self.Jc = None
00087 self.Je = None
00088 self.trim_threshold = 1.0
00089
00090
00091 self.ma_to_m = multiarray_to_matrix.MultiArrayConverter()
00092
00093
00094 self.initComms()
00095 self.initRobot(self.opt.robot)
00096
00097
00098 def initRobot(self, robot_type="pr2"):
00099 if robot_type == "pr2":
00100 self.initPR2()
00101 elif robot_type == "cody":
00102 self.initCody()
00103 elif robot_type == "cody5dof":
00104 self.initCody(5)
00105 elif robot_type == "sim3" or robot_type == "sim3_nolim":
00106 self.initSim(robot_type)
00107 elif robot_type == "crona":
00108 self.initCrona()
00109 else:
00110 rospy.logerr("RobotHapticState: Invalid robot type specified")
00111 sys.exit()
00112
00113
00114 def initPR2(self):
00115
00116 import urdf_arm_darpa_m3 as urdf_arm
00117
00118
00119
00120
00121 self.robot_path = "/pr2"
00122 self.skin_topic_list = rospy.get_param(self.base_path +
00123 self.robot_path +
00124 '/skin_list/' + self.opt.sensor)
00125 self.torso_frame = rospy.get_param(self.base_path +
00126 self.robot_path +
00127 '/torso_frame' )
00128 self.inertial_frame = rospy.get_param(self.base_path +
00129 self.robot_path +
00130 '/inertial_frame')
00131 rospy.loginfo("RobotHapticState: Initialising PR2 haptic state publisher" +
00132 "with the following skin topics: \n%s"
00133 %str(self.skin_topic_list))
00134 self.skin_client = sc.TaxelArrayClient(self.skin_topic_list,
00135 self.torso_frame,
00136 self.tf_listener)
00137 self.skin_client.setTrimThreshold(self.trim_threshold)
00138 rospy.loginfo("RobotHapticState: Initialising robot interface")
00139 if not self.opt.arm:
00140 rospy.logerr("RobotHapticState: No arm specified for PR2")
00141 sys.exit()
00142
00143
00144 self.robot = urdf_arm.URDFArm(self.opt.arm, self.tf_listener)
00145
00146
00147 if self.opt.arm in ['l', 'r']:
00148 arm_path = '/left'
00149 if self.opt.arm == 'r':
00150 arm_path = '/right'
00151
00152 self.joint_limits_max = rospy.get_param(self.base_path +
00153 self.robot_path +
00154 '/joint_limits' +
00155 arm_path + '/max')
00156 self.joint_limits_min = rospy.get_param(self.base_path +
00157 self.robot_path +
00158 '/joint_limits' +
00159 arm_path + '/min')
00160
00161
00162 self.setControllerJointLimits(self.joint_limits_max, self.joint_limits_min)
00163
00164
00165
00166 def initCody(self, num_of_joints=7):
00167 import hrl_cody_arms.cody_arm_client
00168
00169
00170 self.robot_path = '/cody'
00171 self.skin_topic_list = rospy.get_param(self.base_path +
00172 self.robot_path +
00173 '/skin_list/' + self.opt.sensor)
00174 self.torso_frame = rospy.get_param(self.base_path +
00175 self.robot_path +
00176 '/torso_frame' )
00177 self.inertial_frame = rospy.get_param(self.base_path +
00178 self.robot_path +
00179 '/inertial_frame')
00180 rospy.loginfo("RobotHapticState: Initialising Cody haptic state publisher" +
00181 " with the following skin topics: \n%s"
00182 %str(self.skin_topic_list))
00183
00184 self.skin_client = sc.TaxelArrayClient(self.skin_topic_list,
00185 self.torso_frame,
00186 self.tf_listener)
00187 self.skin_client.setTrimThreshold(self.trim_threshold)
00188 rospy.loginfo("RobotHapticState: Initialising robot interface")
00189 if not self.opt.arm:
00190 rospy.logerr("RobotHapticState: No arm specified for Cody")
00191 sys.exit()
00192
00193 if num_of_joints == 7:
00194 self.robot = hrl_cody_arms.cody_arm_client.CodyArmClient_7DOF(self.opt.arm)
00195 elif num_of_joints == 5:
00196 self.robot = hrl_cody_arms.cody_arm_client.CodyArmClient_5DOF(self.opt.arm)
00197
00198
00199 if self.opt.arm in ['l', 'r']:
00200 arm_path = '/left'
00201 if self.opt.arm == 'r':
00202 arm_path = '/right'
00203
00204 self.joint_limits_max = rospy.get_param(self.base_path +
00205 self.robot_path +
00206 '/joint_limits' +
00207 arm_path + '/max')
00208 self.joint_limits_min = rospy.get_param(self.base_path +
00209 self.robot_path +
00210 '/joint_limits' +
00211 arm_path + '/min')
00212
00213
00214 self.setControllerJointLimits(self.joint_limits_max, self.joint_limits_min)
00215
00216
00217
00218 def initSim(self, robot_type='sim3'):
00219 import gen_sim_arms as sim_robot
00220
00221
00222 if robot_type == 'sim3':
00223 import hrl_common_code_darpa_m3.robot_config.three_link_planar_capsule as sim_robot_config
00224 elif robot_type == 'sim3_nolim':
00225 import hrl_common_code_darpa_m3.robot_config.three_link_planar_capsule_nolim as sim_robot_config
00226
00227 self.robot_path = '/sim3'
00228
00229 self.skin_topic_list = rospy.get_param(self.base_path +
00230 self.robot_path +
00231 '/skin_list/' + self.opt.sensor)
00232 self.torso_frame = rospy.get_param(self.base_path +
00233 self.robot_path +
00234 '/torso_frame')
00235 self.inertial_frame = rospy.get_param(self.base_path +
00236 self.robot_path +
00237 '/inertial_frame')
00238 rospy.loginfo("RobotHapticState: Initialising Sim haptic state publisher" +
00239 "with the following skin topics: \n%s"
00240 %str(self.skin_topic_list))
00241
00242 self.skin_client = sc.TaxelArrayClient(self.skin_topic_list,
00243 self.torso_frame,
00244 self.tf_listener)
00245 self.skin_client.setTrimThreshold(self.trim_threshold)
00246
00247
00248 rospy.loginfo("RobotHapticState: Initialising Sim robot interface")
00249 sim_config = sim_robot_config
00250 self.robot = sim_robot.ODESimArm(sim_config)
00251
00252 self.joint_limits_max = rospy.get_param(self.base_path +
00253 self.robot_path +
00254 '/joint_limits/max')
00255 self.joint_limits_min = rospy.get_param(self.base_path +
00256 self.robot_path +
00257 '/joint_limits/min')
00258
00259
00260 self.setControllerJointLimits(self.joint_limits_max, self.joint_limits_min)
00261
00262
00263
00264
00265 def initSimCody(self):
00266 import cody_arm_darpa_m3 as cody_arm
00267
00268
00269 self.robot_path = '/simcody'
00270 self.skin_topic_list = rospy.get_param(self.base_path +
00271 self.robot_path +
00272 '/skin_list')
00273 self.torso_frame = rospy.get_param(self.base_path +
00274 self.robot_path +
00275 '/torso_frame' )
00276 self.inertial_frame = rospy.get_param(self.base_path +
00277 self.robot_path +
00278 '/inertial_frame')
00279 rospy.loginfo("RobotHapticState: Initialising Sim haptic state publisher" +
00280 "with the following skin topics: \n%s"
00281 %str(self.skin_topic_list))
00282 self.skin_client = sc.TaxelArrayClient(self.skin_topic_list,
00283 self.torso_frame,
00284 self.tf_listener)
00285 self.skin_client.setTrimThreshold(self.trim_threshold)
00286
00287
00288 rospy.loginfo("RobotHapticState: Initialising robot interface")
00289 if not self.opt.arm:
00290 rospy.logerr("RobotHapticState: No arm specified for Sim Cody")
00291 sys.exit()
00292
00293 self.robot = cody_arm.CodyArmClient(self.opt.arm)
00294
00295 def initCrona(self):
00296 import urdf_arm_darpa_m3 as urdf_arm
00297
00298 self.robot_path = "/crona"
00299 self.skin_topic_list = rospy.get_param(self.base_path +
00300 self.robot_path +
00301 '/skin_list/' + self.opt.sensor)
00302 self.torso_frame = rospy.get_param(self.base_path +
00303 self.robot_path +
00304 '/torso_frame' )
00305 self.inertial_frame = rospy.get_param(self.base_path +
00306 self.robot_path +
00307 '/inertial_frame')
00308 self.skin_client = sc.TaxelArrayClient([],
00309 self.torso_frame,
00310 self.tf_listener)
00311 rospy.loginfo("RobotHapticState: Initialising CRONA haptic state publisher with the following skin topics: \n%s"
00312 %str(self.skin_topic_list))
00313
00314 rospy.loginfo("RobotHapticState: Initialising robot interface")
00315 if not self.opt.arm:
00316 rospy.logerr("RobotHapticState: No arm specified for CRONA")
00317 sys.exit()
00318 self.robot = urdf_arm.URDFArm(self.opt.arm, self.tf_listener, base_link=self.torso_frame, end_link=self.opt.arm+'_hand_link')
00319 self.skins = []
00320 self.Jc = []
00321
00322
00323 if self.opt.arm in ['l', 'r']:
00324 arm_path = '/left'
00325 if self.opt.arm == 'r':
00326 arm_path = '/right'
00327
00328 self.joint_limits_max = rospy.get_param(self.base_path +
00329 self.robot_path +
00330 '/joint_limits' +
00331 arm_path + '/max')
00332 self.joint_limits_min = rospy.get_param(self.base_path +
00333 self.robot_path +
00334 '/joint_limits' +
00335 arm_path + '/min')
00336
00337
00338 self.setControllerJointLimits(self.joint_limits_max, self.joint_limits_min)
00339
00340
00341
00342
00343
00344 def initComms(self):
00345 if self.node_name != None:
00346 rospy.init_node(self.node_name)
00347 self.tf_listener = TransformListener()
00348 self.state_pub = rospy.Publisher('/haptic_mpc/robot_state',
00349 haptic_msgs.RobotHapticState)
00350 self.gripper_pose_pub = rospy.Publisher('/haptic_mpc/gripper_pose',
00351 geom_msgs.PoseStamped)
00352
00353
00354
00355 def setControllerJointLimits(self, joint_limits_max, joint_limits_min):
00356
00357 rospy.set_param(self.base_path + '/joint_limits/max', joint_limits_max)
00358 rospy.set_param(self.base_path + '/joint_limits/min', joint_limits_min)
00359
00360
00361
00362
00363 def getMessageHeader(self):
00364 header = Header()
00365 header.stamp = rospy.get_rostime()
00366 return header
00367
00368
00369
00370 def updateEndEffectorJacobian(self):
00371 self.Je = [self.robot.kinematics.jacobian(self.joint_angles, self.end_effector_position)]
00372
00373
00374
00375 def updateContactJacobians(self, skin_data):
00376
00377
00378
00379 Jc_l = []
00380 loc_l, jt_l = self.getTaxelLocationAndJointList(skin_data)
00381
00382 if len(loc_l) != len(jt_l):
00383 rospy.logfatal("Haptic State Publisher: Dimensions don't match. %s, %s" % (len(loc_l), len(jt_l)))
00384 sys.exit()
00385
00386 for jt_li, loc_li in it.izip(jt_l, loc_l):
00387 Jc = self.robot.kinematics.jacobian(self.joint_angles, loc_li)
00388 Jc[:, jt_li+1:] = 0.0
00389 Jc = Jc[0:3, 0:len(self.joint_stiffness)]
00390 Jc_l.append(Jc)
00391 self.Jc = Jc_l
00392
00393
00394 def updateTorsoPose(self):
00395
00396 self.tf_listener.waitForTransform(self.inertial_frame, self.torso_frame,
00397 rospy.Time(), rospy.Duration(10.0))
00398 t1, q1 = self.tf_listener.lookupTransform(self.inertial_frame,
00399 self.torso_frame,
00400 rospy.Time(0))
00401 torso_pose = geom_msgs.Pose()
00402 torso_pose.position = geom_msgs.Point(*t1)
00403 torso_pose.orientation = geom_msgs.Quaternion(*q1)
00404 return torso_pose
00405
00406
00407
00408
00409
00410
00411
00412
00413 def updateJointStates(self):
00414 self.joint_names = self.robot.get_joint_names()
00415 self.joint_angles = self.robot.get_joint_angles()
00416 self.joint_stiffness, self.joint_damping = self.robot.get_joint_impedance()
00417 self.joint_velocities = self.robot.get_joint_velocities()
00418 q_des = self.robot.get_ep()
00419 if q_des != None:
00420 self.desired_joint_angles = q_des
00421
00422
00423
00424 def updateEndEffectorPose(self):
00425 pos, rot = self.robot.kinematics.FK(self.joint_angles)
00426 self.end_effector_position = pos
00427 self.end_effector_orient_cart = rot
00428 self.end_effector_orient_quat = tr.matrix_to_quaternion(rot)
00429
00430
00431
00432
00433
00434
00435
00436 def getTaxelLocationAndJointList(self, skin_data):
00437 locations = []
00438 joint_nums = []
00439
00440 for ta_msg in skin_data.values():
00441
00442 ta_locs = self.skin_client.getContactLocationsFromTaxelArray(ta_msg)
00443
00444 ta_jts = []
00445 for contact_index in range(len(ta_msg.centers_x)):
00446 jt_num = len(self.joint_angles)-1
00447
00448
00449 if len(ta_msg.link_names) >= len(ta_msg.centers_x):
00450 link_name = ta_msg.link_names[contact_index]
00451
00452
00453
00454
00455 for idx, joint_name in enumerate(self.joint_names):
00456 if joint_name in link_name:
00457 jt_num = idx
00458 break
00459
00460 ta_jts.append(jt_num)
00461
00462
00463 locations.extend(ta_locs)
00464 joint_nums.extend(ta_jts)
00465
00466 return locations, joint_nums
00467
00468
00469
00470
00471 def modifyPR2Taxels(self, skin_data):
00472
00473 return skin_data
00474
00475
00476
00477
00478
00479
00480 def modifyRobotSpecificTaxels(self, skin_data):
00481 if self.opt.robot == 'pr2':
00482 return self.modifyPR2Taxels(skin_data)
00483 return skin_data
00484
00485
00486 def updateHapticState(self):
00487 self.updateJointStates()
00488
00489 self.updateEndEffectorPose()
00490 self.updateEndEffectorJacobian()
00491
00492
00493 skin_data = self.skin_client.getTrimmedSkinData()
00494
00495 skin_data = self.modifyRobotSpecificTaxels(skin_data)
00496 self.updateContactJacobians(skin_data)
00497
00498 self.skins = skin_data.values()
00499
00500
00501
00502 def getHapticStateMessage(self):
00503
00504 self.updateHapticState()
00505
00506 msg = haptic_msgs.RobotHapticState()
00507
00508 msg.header = self.getMessageHeader()
00509 msg.header.frame_id = self.torso_frame
00510
00511
00512
00513
00514 msg.joint_names = self.joint_names
00515 msg.joint_angles = self.joint_angles
00516 msg.desired_joint_angles = self.desired_joint_angles
00517 msg.joint_velocities = self.joint_velocities
00518 msg.joint_stiffness = self.joint_stiffness
00519 msg.joint_damping = self.joint_damping
00520
00521 msg.torso_pose = self.torso_pose
00522
00523
00524
00525 msg.hand_pose.position = geom_msgs.Point(*(self.end_effector_position.A1))
00526 msg.hand_pose.orientation = geom_msgs.Quaternion(*self.end_effector_orient_quat)
00527
00528
00529 msg.end_effector_jacobian = self.ma_to_m.matrixListToMultiarray(self.Je)
00530
00531
00532
00533
00534
00535
00536
00537
00538
00539
00540 msg.skins = self.skins
00541 msg.contact_jacobians = self.ma_to_m.matrixListToMultiarray(self.Jc)
00542
00543 return msg
00544
00545
00546 def publishRobotState(self):
00547 msg = self.getHapticStateMessage()
00548
00549
00550 for i in range(len(msg.joint_names)):
00551 msg.joint_names[i] = str(msg.joint_names[i])
00552 self.state_pub.publish(msg)
00553
00554
00555 ps_msg = geom_msgs.PoseStamped()
00556 ps_msg.header = self.getMessageHeader()
00557 ps_msg.header.frame_id = self.torso_frame
00558
00559 ps_msg.pose.position = geom_msgs.Point(*(self.end_effector_position.A1))
00560 ps_msg.pose.orientation = geom_msgs.Quaternion(*self.end_effector_orient_quat)
00561
00562 self.gripper_pose_pub.publish(ps_msg)
00563
00564
00565
00566
00567 def signal_handler(self, signal, frame):
00568 print 'Ctrl+C pressed - exiting'
00569 sys.exit(0)
00570
00571
00572 def start(self):
00573 signal.signal(signal.SIGINT, self.signal_handler)
00574
00575 rospy.loginfo("RobotHapticState: Starting Robot Haptic State publisher")
00576 rate = rospy.Rate(self.rate)
00577
00578
00579
00580 rospy.loginfo("RobotHapticState: Waiting for robot state")
00581 joint_stiffness, joint_damping = self.robot.get_joint_impedance()
00582 while (self.robot.get_joint_angles() == None or
00583 self.robot.get_joint_velocities() == None or
00584 joint_stiffness == None):
00585 joint_stiffness, joint_damping = self.robot.get_joint_impedance()
00586 rate.sleep()
00587
00588 rospy.loginfo("RobotHapticState: Got robot state")
00589
00590 if self.robot.get_ep() == None:
00591 rospy.loginfo("RobotHapticState: Setting desired joint angles to current joint_angles")
00592 self.robot.set_ep(self.robot.get_joint_angles())
00593
00594 rospy.loginfo("RobotHapticState: Starting publishing")
00595 while not rospy.is_shutdown():
00596 self.publishRobotState()
00597
00598 rate.sleep()
00599
00600
00601 if __name__ == "__main__":
00602
00603 import optparse
00604 p = optparse.OptionParser()
00605 haptic_mpc_util.initialiseOptParser(p)
00606 opt = haptic_mpc_util.getValidInput(p)
00607
00608 if not opt.robot or not opt.sensor or not opt.arm:
00609 p.error("Robot haptic state publisher requires a specified robot, sensor, AND arm to use.")
00610
00611 robot_state = RobotHapticStateServer(opt, "robot_haptic_state_server")
00612 robot_state.start()