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 import sys, os
00026 import numpy, math
00027 import copy, threading
00028 import collections
00029
00030 import roslib; roslib.load_manifest('hrl_haptic_mpc')
00031 import rospy
00032 import tf
00033
00034 import hrl_lib.util as ut
00035 import hrl_lib.transforms as tr
00036
00037 import trajectory_msgs.msg
00038 import geometry_msgs.msg
00039 import trajectory_msgs.msg
00040 import std_msgs.msg
00041 import hrl_haptic_manipulation_in_clutter_msgs.msg as haptic_msgs
00042 import hrl_msgs.msg
00043
00044 import haptic_mpc_util
00045
00046
00047
00048 class WaypointGenerator():
00049 node_name = None
00050 opt = None
00051 rate = 25.0
00052 msg_seq = 0
00053
00054
00055 param_path = ""
00056 base_path = "/haptic_mpc"
00057 cody_param_path = "/cody"
00058 pr2_param_path = "/pr2"
00059 sim_param_path = "/sim3"
00060 simcody_param_path = "/simcody"
00061 crona_param_path = "/crona"
00062
00063
00064 current_pose_topic = "/haptic_mpc/robot_state"
00065 goal_pose_topic = "/haptic_mpc/goal_pose"
00066 goal_pose_array_topic = "/haptic_mpc/goal_pose_array"
00067 waypoint_pose_topic = "/haptic_mpc/traj_pose"
00068
00069
00070 robot = None
00071 robot_name = None
00072 sensor = None
00073 eq_gen_type = None
00074 default_eq_gen_type = 'mpc_qs_1'
00075
00076 skin_topic_list = None
00077 scl = None
00078 epcon = None
00079
00080
00081 max_pos_step = 0.05
00082
00083 max_ang_step = 0.02
00084 at_waypoint_threshold = 0.02
00085 at_waypoint_ang_threshold = numpy.radians(5.0)
00086
00087 max_posture_step = numpy.radians(5.0)
00088 at_posture_threshold = numpy.radians(2.0)
00089
00090 mode = "none"
00091
00092 current_trajectory_deque = collections.deque()
00093 gripper_pose = None
00094 goal_pose = None
00095 current_gripper_waypoint = None
00096
00097 traj_lock = threading.RLock()
00098 goal_lock = threading.RLock()
00099 state_lock = threading.RLock()
00100
00101
00102
00103 def __init__(self, node_name, opt):
00104 rospy.loginfo("Initialising trajectory generator for Haptic MPC")
00105 self.opt = opt
00106 self.node_name = node_name
00107 rospy.init_node(node_name)
00108
00109
00110 if (self.opt.robot == "cody"):
00111 self.initCody()
00112 elif (self.opt.robot == "pr2"):
00113 self.initPR2()
00114 elif(self.opt.robot == "sim3" or self.opt.robot == "sim3_nolim"):
00115 self.initSim3()
00116 elif(self.opt.robot == "simcody"):
00117 self.initSimCody()
00118 elif(self.opt.robot == "crona"):
00119 self.initCrona()
00120 else:
00121 rospy.logerr("Invalid Robot type: %s" % robot)
00122
00123
00124 self.initComms()
00125
00126 return
00127
00128
00129 def initCody(self):
00130 rospy.loginfo("Trajectory generator for: Cody")
00131
00132
00133
00134
00135 def initPR2(self):
00136 from pykdl_utils.kdl_kinematics import create_kdl_kin
00137
00138 rospy.loginfo("Trajectory generator for: PR2")
00139 if not self.opt.arm:
00140 rospy.logerr('Arm not specified for PR2')
00141 sys.exit()
00142
00143 self.robot_kinematics = create_kdl_kin('torso_lift_link', self.opt.arm+'_gripper_tool_frame')
00144 self.tf_listener = tf.TransformListener()
00145
00146 if self.opt.arm == None:
00147 rospy.logerr('Need to specify --arm_to_use.\nExiting...')
00148 sys.exit()
00149
00150
00151 def initSim3(self):
00152 rospy.loginfo("Trajectory generator for: Simulation 3DOF")
00153
00154
00155 def initCrona(self):
00156 from pykdl_utils.kdl_kinematics import create_kdl_kin
00157
00158 rospy.loginfo("Trajectory generator for: cRoNA")
00159 if not self.opt.arm:
00160 rospy.logerr('Arm not specified for cRoNA')
00161 sys.exit()
00162
00163
00164 self.robot_kinematics = create_kdl_kin('base_link', self.opt.arm+'_hand_link')
00165 self.tf_listener = tf.TransformListener()
00166
00167 if self.opt.arm == None:
00168 rospy.logerr('Need to specify --arm_to_use.\nExiting...')
00169 sys.exit()
00170
00171
00172 def initComms(self):
00173
00174 self.pose_waypoint_pub = rospy.Publisher(self.waypoint_pose_topic, geometry_msgs.msg.PoseStamped)
00175 self.goal_posture_pub = rospy.Publisher("/haptic_mpc/goal_posture", hrl_msgs.msg.FloatArray)
00176 self.mpc_weights_pub = rospy.Publisher("/haptic_mpc/weights", haptic_msgs.HapticMpcWeights)
00177
00178
00179 rospy.Subscriber(self.goal_pose_topic, geometry_msgs.msg.PoseStamped, self.goalPoseCallback)
00180
00181 rospy.Subscriber(self.current_pose_topic, haptic_msgs.RobotHapticState, self.robotStateCallback)
00182
00183 rospy.Subscriber('/haptic_mpc/joint_trajectory', trajectory_msgs.msg.JointTrajectory, self.jointTrajectoryCallback)
00184
00185 rospy.Subscriber(self.goal_pose_array_topic, geometry_msgs.msg.PoseArray, self.poseTrajectoryCallback)
00186 self.pose_traj_viz_pub = rospy.Publisher('/haptic_mpc/current_pose_traj', geometry_msgs.msg.PoseArray, latch=True)
00187
00188
00189
00190
00191 def goalPoseCallback(self, msg):
00192 rospy.loginfo("Got new goal pose")
00193 if (not 'torso_lift_link' in msg.header.frame_id) and (not '/torso_chest_link' in msg.header.frame_id) and (not '/base_link' in msg.header.frame_id):
00194 print "msg.header.frame_id"
00195 print msg.header.frame_id
00196 try:
00197 self.tf_listener.waitForTransform(msg.header.frame_id, '/torso_lift_link', msg.header.stamp, rospy.Duration(5.0))
00198 except (tf.ConnectivityException, tf.LookupException, tf.ExtrapolationException) as e:
00199 rospy.logerr('[arm_trajectory_generator]: TF Exception: %s' %e)
00200 ps = geometry_msgs.msg.PoseStamped(msg.header, msg.pose)
00201 ps.header.stamp = rospy.Time(0)
00202 new_pose_stamped = self.tf_listener.transformPose('/torso_lift_link', ps)
00203 msg = new_pose_stamped
00204
00205 with self.goal_lock:
00206 self.goal_pose = msg.pose
00207
00208 with self.traj_lock:
00209 self.current_trajectory_deque.clear()
00210
00211
00212
00213 def robotStateCallback(self, msg):
00214 with self.state_lock:
00215 self.gripper_pose = msg.hand_pose
00216 self.joint_angles = msg.joint_angles
00217
00218
00219
00220 def poseTrajectoryCallback(self, msg):
00221 rospy.loginfo("Got new pose trajectory")
00222 self.goal_pose = None
00223 with self.traj_lock:
00224 self.current_trajectory_msg = msg
00225 self.current_trajectory_deque.clear()
00226
00227 if len(msg.poses) == 0:
00228 rospy.logwarn("Received empty pose array. Clearing trajectory buffer")
00229 return
00230
00231
00232 if not 'torso_lift_link' in msg.header.frame_id:
00233 print "msg.header.frame_id"
00234 print msg.header.frame_id
00235 try:
00236 self.tf_listener.waitForTransform(msg.header.frame_id, '/torso_lift_link',
00237 msg.header.stamp, rospy.Duration(5.0))
00238 except (tf.ConnectivityException, tf.LookupException, tf.ExtrapolationException) as e:
00239 rospy.logerr('[arm_trajectory_generator]: TF Exception: %s' %e)
00240
00241 pose_array = []
00242 for pose in msg.poses:
00243 ps = geometry_msgs.msg.PoseStamped(msg.header, pose)
00244 ps.header.stamp = rospy.Time(0)
00245 new_pose_stamped = self.tf_listener.transformPose('/torso_lift_link', ps)
00246 pose_array.append(new_pose_stamped.pose)
00247
00248
00249 pose_array_msg = geometry_msgs.msg.PoseArray()
00250 pose_array_msg.header.frame_id = "/torso_lift_link"
00251 pose_array_msg.poses = pose_array
00252 self.pose_traj_viz_pub.publish(pose_array_msg)
00253
00254 self.current_trajectory_deque.extend(pose_array)
00255
00256 with self.goal_lock:
00257 self.goal_pose = None
00258
00259
00260
00261
00262 def jointTrajectoryCallback(self, msg):
00263 rospy.loginfo("Got new joint trajectory")
00264 with self.traj_lock:
00265 self.current_trajectory_msg = msg
00266 self.current_trajectory_deque.clear()
00267
00268 for point in msg.points:
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285 self.current_trajectory_deque.append(point)
00286
00287
00288 with self.goal_lock:
00289 self.goal_pose = None
00290
00291
00292 def setControllerWeights(self, position_weight, orient_weight, posture_weight):
00293 weights_msg = haptic_msgs.HapticMpcWeights()
00294 weights_msg.header.stamp = rospy.Time.now()
00295 weights_msg.position_weight = position_weight
00296 weights_msg.orient_weight = orient_weight
00297 weights_msg.posture_weight = posture_weight
00298 self.mpc_weights_pub.publish(weights_msg)
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308 def straightLineTrajectory(self, current_pose, goal_pose, max_pos_step, max_ang_step):
00309 desired_pose = geometry_msgs.msg.Pose()
00310
00311 current_pos_vector = numpy.array([current_pose.position.x, current_pose.position.y, current_pose.position.z])
00312 goal_pos_vector = numpy.array([goal_pose.position.x, goal_pose.position.y, goal_pose.position.z])
00313
00314 position_waypoint = self.getPositionStep(current_pos_vector, goal_pos_vector, max_pos_step)
00315
00316 desired_pose.position.x = position_waypoint[0]
00317 desired_pose.position.y = position_waypoint[1]
00318 desired_pose.position.z = position_waypoint[2]
00319
00320
00321 current_orientation = [current_pose.orientation.x, current_pose.orientation.y, current_pose.orientation.z, current_pose.orientation.w]
00322 goal_orientation = [goal_pose.orientation.x, goal_pose.orientation.y, goal_pose.orientation.z, goal_pose.orientation.w]
00323
00324 orientation_waypoint = goal_orientation
00325
00326 desired_pose.orientation.x = orientation_waypoint[0]
00327 desired_pose.orientation.y = orientation_waypoint[1]
00328 desired_pose.orientation.z = orientation_waypoint[2]
00329 desired_pose.orientation.w = orientation_waypoint[3]
00330
00331
00332 return desired_pose
00333
00334
00335
00336
00337
00338
00339 def getPositionStep(self, current_pos, goal_pos, max_pos_step):
00340 difference_to_goal = goal_pos - current_pos
00341 dist_to_goal = numpy.sqrt(numpy.vdot(difference_to_goal, difference_to_goal))
00342
00343 if dist_to_goal > max_pos_step:
00344 step_vector = difference_to_goal / dist_to_goal * max_pos_step
00345 else:
00346 step_vector = difference_to_goal
00347 desired_position = current_pos + step_vector
00348
00349 return desired_position
00350
00351
00352
00353
00354
00355
00356 def getOrientationStep(self, q_h_orient, q_g_orient, max_ang_step):
00357 ang = ut.quat_angle(q_h_orient, q_g_orient)
00358
00359 ang_mag = abs(ang)
00360 step_fraction = 0.001
00361 if step_fraction * ang_mag > max_ang_step:
00362
00363 step_fraction = max_ang_step / ang_mag
00364
00365 interp_q_goal = tr.tft.quaternion_slerp(q_h_orient, q_g_orient, step_fraction)
00366 return interp_q_goal
00367
00368
00369 def getMessageHeader(self):
00370 header = std_msgs.msg.Header()
00371 header.seq = self.msg_seq
00372 self.msg_seq += 1
00373 header.stamp = rospy.get_rostime()
00374
00375 header.frame_id = "/base_link"
00376 return header
00377
00378
00379 def distanceBetweenPostures(self, postureA, postureB):
00380 max_dist = 0.0
00381
00382 for i in range(1, len(postureA)):
00383 dist = abs(postureA[i] - postureB[i])
00384 if dist > max_dist:
00385 max_dist = dist
00386
00387 return max_dist
00388
00389
00390
00391
00392
00393 def distanceBetweenPoses(self, poseA, poseB):
00394 xdiff = poseA.position.x - poseB.position.x
00395 ydiff = poseA.position.y - poseB.position.y
00396 zdiff = poseA.position.z - poseB.position.z
00397 return numpy.sqrt(xdiff**2 + ydiff **2 + zdiff**2)
00398
00399
00400
00401
00402
00403 def angularDistanceBetweenPoses(self, poseA, poseB):
00404 quatA = [poseA.orientation.x, poseA.orientation.y, poseA.orientation.z, poseA.orientation.w]
00405 quatB = [poseB.orientation.x, poseB.orientation.y, poseB.orientation.z, poseB.orientation.w]
00406 ang_diff = ut.quat_angle(quatA, quatB)
00407 return ang_diff
00408
00409
00410
00411
00412
00413
00414 def getWaypointFromTrajectory(self):
00415 with self.state_lock:
00416 curr_gripper_pose = copy.copy(self.gripper_pose)
00417 with self.traj_lock:
00418
00419 if len(self.current_trajectory_deque) > 0:
00420
00421 if len(self.current_trajectory_deque) > 1:
00422
00423 if self.distanceBetweenPoses(curr_gripper_pose, self.current_trajectory_deque[0]) < self.at_waypoint_threshold:
00424
00425
00426
00427
00428 while self.distanceBetweenPoses(curr_gripper_pose, self.current_trajectory_deque[0]) < self.max_pos_step and len(self.current_trajectory_deque) > 1:
00429 print "Trimming trajectory - dist: %s, len(deque): %s" % (self.distanceBetweenPoses(self.gripper_pose, self.current_trajectory_deque[0]), len(self.current_trajectory_deque))
00430 self.current_trajectory_deque.popleft()
00431
00432 desired_pose = self.current_trajectory_deque[0]
00433 return desired_pose
00434
00435 else:
00436 return None
00437
00438
00439 def getPostureFromTrajectory(self):
00440 with self.state_lock:
00441 curr_posture = copy.copy(self.joint_angles)
00442 with self.traj_lock:
00443
00444 if len(self.current_trajectory_deque) > 0:
00445
00446 if len(self.current_trajectory_deque) > 1:
00447
00448 if self.distanceBetweenPostures(curr_posture, self.current_trajectory_deque[0].positions) < self.at_posture_threshold:
00449
00450
00451
00452
00453
00454 self.current_trajectory_deque.popleft()
00455 print "Moving to next waypoint."
00456 print numpy.degrees(self.current_trajectory_deque[0].positions)
00457
00458 desired_posture = self.current_trajectory_deque[0]
00459 return desired_posture
00460
00461 else:
00462 return None
00463
00464
00465
00466
00467
00468
00469
00470 def generateWaypoint(self):
00471
00472
00473 with self.state_lock:
00474 tmp_curr_pose = copy.copy(self.gripper_pose)
00475 with self.goal_lock:
00476 tmp_goal_pose = copy.copy(self.goal_pose)
00477
00478 if tmp_curr_pose == None:
00479 return
00480
00481
00482 if tmp_goal_pose != None:
00483 desired_pose = self.straightLineTrajectory(tmp_curr_pose, tmp_goal_pose, self.max_pos_step, self.max_ang_step)
00484 waypoint_msg = geometry_msgs.msg.PoseStamped()
00485 waypoint_msg.header = self.getMessageHeader()
00486 waypoint_msg.pose = desired_pose
00487 self.pose_waypoint_pub.publish(waypoint_msg)
00488 elif len(self.current_trajectory_deque) > 0:
00489
00490 if type(self.current_trajectory_deque[0]) == geometry_msgs.msg.Pose:
00491 if self.mode != "pose":
00492 self.setControllerWeights(5.0, 4.0, 0.0)
00493 self.mode = "pose"
00494 desired_pose = self.getWaypointFromTrajectory()
00495 if desired_pose == None and tmp_goal_pose != None:
00496 desired_pose = self.straightLineTrajectory(tmp_curr_pose, tmp_goal_pose, self.max_pos_step, self.max_ang_step)
00497
00498
00499 if desired_pose == None:
00500 return
00501
00502
00503 waypoint_msg = geometry_msgs.msg.PoseStamped()
00504 waypoint_msg.header = self.getMessageHeader()
00505 waypoint_msg.pose = desired_pose
00506 self.pose_waypoint_pub.publish(waypoint_msg)
00507
00508 elif type(self.current_trajectory_deque[0]) == trajectory_msgs.msg.JointTrajectoryPoint:
00509 if self.mode != "posture":
00510 self.setControllerWeights(0.0, 0.0, 1.0)
00511 self.mode = "posture"
00512 desired_posture = self.getPostureFromTrajectory()
00513 if desired_posture == None:
00514 rospy.loginfo("desired_posture is none")
00515 return
00516
00517 waypoint_msg = hrl_msgs.msg.FloatArray()
00518
00519 waypoint_msg.data = list(desired_posture.positions)
00520
00521 self.goal_posture_pub.publish(waypoint_msg)
00522 else:
00523 rospy.loginfo("Object in the waypoint deque is neither geometry_msgs.msg.Pose or trajectory_msgs.msg.JointTrajectoryPoint. Who broke it?!")
00524
00525
00526
00527
00528 def start(self):
00529 rate = rospy.Rate(self.rate)
00530 rospy.loginfo("Beginning publishing waypoints")
00531 while not rospy.is_shutdown():
00532 self.generateWaypoint()
00533
00534 rate.sleep()
00535
00536 if __name__ == '__main__':
00537
00538 import optparse
00539 p = optparse.OptionParser()
00540
00541 haptic_mpc_util.initialiseOptParser(p)
00542 opt = haptic_mpc_util.getValidInput(p)
00543
00544
00545 traj_mgr = WaypointGenerator('mpc_traj_gen', opt)
00546 traj_mgr.start()
00547
00548
00549
00550
00551