robot_haptic_state_node.py
Go to the documentation of this file.
00001 #!/usr/bin/env python
00002 
00003 #   Copyright 2013 Georgia Tech Research Corporation
00004 #
00005 #   Licensed under the Apache License, Version 2.0 (the "License");
00006 #   you may not use this file except in compliance with the License.
00007 #   You may obtain a copy of the License at
00008 #
00009 #     http://www.apache.org/licenses/LICENSE-2.0
00010 #
00011 #   Unless required by applicable law or agreed to in writing, software
00012 #   distributed under the License is distributed on an "AS IS" BASIS,
00013 #   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00014 #   See the License for the specific language governing permissions and
00015 #   limitations under the License.
00016 #
00017 #  http://healthcare-robotics.com/
00018 
00019 ## @package hrl_haptic_mpc
00020 #
00021 # @author Jeff Hawke
00022 # @version 0.1
00023 # @copyright Apache Licence
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 ## @class RobotHapticStateServer Haptic state publisher: publishes all relevant haptic state information on a common interface independent of robot type.
00047 class RobotHapticStateServer():
00048   ## Constructor for robot haptic state server
00049   def __init__(self, opt, node_name=None):
00050     self.opt = opt
00051     # Set up all ros comms to start with
00052     self.node_name = node_name
00053     self.tf_listener = None
00054     self.state_pub = None
00055     self.rate = 100.0 # 100 Hz.
00056     self.msg_seq = 0 # Sequence counter
00057 
00058     # ROS Param server paths.
00059     self.base_path = "/haptic_mpc"
00060 
00061     # Skin data
00062     self.skin_topic_list = [] # List of topic names
00063     self.skin_client = None
00064 
00065     # Robot object. Contains all the subscribers and robot specific kinematics, etc
00066     self.robot = None
00067 
00068     # Joint data
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     # End effector pose
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     # Jacobian storage
00086     self.Jc = None # Contact jacobians
00087     self.Je = None # End effector jacobian
00088     self.trim_threshold = 1.0 #this is 1.0 for forces
00089 
00090     # Jacobian MultiArray to Matrix converter
00091     self.ma_to_m = multiarray_to_matrix.MultiArrayConverter()
00092 
00093     # Initialise various parameters.
00094     self.initComms()
00095     self.initRobot(self.opt.robot)
00096 
00097   ## Initialise all robot specific parameters (skin topics, robot interfaces, etc). Calls the appropriate init function.
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   ## Initialise parameters for the state publisher when used on the PR2.
00114   def initPR2(self):
00115     # Robot kinematic classes and skin clients. These are specific to each robot
00116     import urdf_arm_darpa_m3 as urdf_arm
00117 
00118     #import pr2_arm_darpa_m3_deprecated as pr2_arm # DEPRECATED
00119 
00120     # Load parameters from ROS Param server
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     # Create the robot object. Provides interfaces to the robot arm and various kinematic functions.
00144     self.robot = urdf_arm.URDFArm(self.opt.arm, self.tf_listener)
00145 
00146     # Push joint angles to the param server.
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     # Push the arm specific param to the location the controller looks.
00162     self.setControllerJointLimits(self.joint_limits_max, self.joint_limits_min)
00163 
00164 
00165   ## Initialise parameters for the state publisher when used on Cody.
00166   def initCody(self, num_of_joints=7):
00167     import hrl_cody_arms.cody_arm_client
00168 
00169     # Load the skin list from the param server
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     # Push joint angles to the param server.
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     # Push the arm specific param to the location the controller looks.
00214     self.setControllerJointLimits(self.joint_limits_max, self.joint_limits_min)
00215 
00216   ## Initialise parameters for the state publisher when used in simulation
00217   #with the 3DOF arm.
00218   def initSim(self, robot_type='sim3'):
00219     import gen_sim_arms as sim_robot
00220     
00221     # Load the skin list from the param server
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     # TODO: Add config switching here.
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     # Push the arm specific param to the location the controller looks.
00260     self.setControllerJointLimits(self.joint_limits_max, self.joint_limits_min)
00261 
00262 
00263   #Initialise parameters for the state publisher when used in simulation
00264   #with the 7DOF cody arm.
00265   def initSimCody(self):
00266     import cody_arm_darpa_m3 as cody_arm
00267 
00268     # Load the skin list from the param server
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     # TODO: Add config switching here.
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     # Push joint angles to the param server.
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     # Push the arm specific param to the location the controller looks.
00338     self.setControllerJointLimits(self.joint_limits_max, self.joint_limits_min)
00339 
00340   # Initialise publishers for the robot haptic state,
00341   # the current gripper pose, and a TF listener.
00342   # NB: The skin client and robot clients will have their own
00343   # publishers/subscribers specific to them.
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   ## Pushes the given joint limits to a known location on the param server. 
00354   # The control loads these on startup.
00355   def setControllerJointLimits(self, joint_limits_max, joint_limits_min):
00356     # Push the arm specific param to the location the controller looks.
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   # Returns a header type with the current timestamp.
00362   # Does not set the frame_id
00363   def getMessageHeader(self):
00364     header = Header()
00365     header.stamp = rospy.get_rostime()
00366     return header
00367 
00368   # Updates the stored end effector Jacobian from the current joint angles
00369   # and end effector position
00370   def updateEndEffectorJacobian(self):
00371     self.Je = [self.robot.kinematics.jacobian(self.joint_angles, self.end_effector_position)]
00372 
00373   ## Compute contact Jacobians based on the provided taxel array dictionary
00374   # @param skin_data Dictionary containing taxel array messages indexed by topic name
00375   def updateContactJacobians(self, skin_data):
00376     # loc_l = list of taxel locations relative the "torso_lift_link" frame.
00377     # jt_l = list of joints beyond which the jacobian columns are zero.
00378     # loc_l. jt_l from skin client.
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)] # trim the jacobian to suit the number of DOFs.
00390       Jc_l.append(Jc)
00391     self.Jc = Jc_l
00392 
00393   ## Returns a Pose object for the torso pose in the stated inertial frame
00394   def updateTorsoPose(self):
00395     # Get the transformation from the desired frame to current frame
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   ## Store latest joint states from the specified robot class
00407   # @var joint_names: Joint names
00408   # @var joint_angles: Joint angles
00409   # @var joint_velocities: Joint velocities
00410   # @var joint_stiffness: Joint stiffness
00411   # @var joint_damping: Joint damping
00412   # @var q_des: Desired joint angles
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   # Compute and store the end effector position, orientation, and jacobian
00423   # from the current joint angles.
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   ## Returns a list of taxel locations and a list of joint numbers after which the
00431   # joint torque will have no effect on the contact force
00432   # @param skin_data Dictionary of TaxelArrays indexed by topic
00433   # @retval locations List of taxel locations where a force is present
00434   # @retval joint_nums List of joints after which the joint torque will have no effect on the contact force 
00435   # @return These arrays will both be the same length (as the joint number corresponds 
00436   def getTaxelLocationAndJointList(self, skin_data):
00437     locations = []
00438     joint_nums = []
00439     
00440     for ta_msg in skin_data.values():
00441       # Get points list
00442       ta_locs = self.skin_client.getContactLocationsFromTaxelArray(ta_msg)
00443       # Create list of joints beyond which the joint torque has no effect on contact force
00444       ta_jts = []
00445       for contact_index in range(len(ta_msg.centers_x)):
00446         jt_num = len(self.joint_angles)-1 # Index of last joint, 0 indexed.
00447         
00448         # Verify we have the same number of link names as taxel contacts If not, make no assumptions about joints.
00449         if len(ta_msg.link_names) >= len(ta_msg.centers_x):
00450           link_name = ta_msg.link_names[contact_index]
00451         
00452           # Iterate over the known joint names looking for the link this is associated with.
00453           # NB: links should be named based on their joint. 
00454           # NB: 
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       # Attach these lists to the end of the global list (incorporating multiple taxel arrays)
00463       locations.extend(ta_locs)
00464       joint_nums.extend(ta_jts)
00465       
00466     return locations, joint_nums
00467 
00468   ## Modify taxel data for PR2 specific situations
00469   # TODO: Survy to implement selective taxel ignoring.
00470   # @param skin_data Dictionary containing taxel array messages indexed by topic name
00471   def modifyPR2Taxels(self, skin_data):
00472     #print "modifyPR2Taxels"
00473     return skin_data
00474 
00475   ## Modifies data from the taxel array based on robot specific configurations.
00476   # An example of this is ignoring the PR2 wrist taxels when the wrist
00477   # is near its joint limit as the wrist itself will trigger the taxel.
00478   # @param skin_data Dict containing taxel array messages indexed by topic name
00479   # @return skin_data Modified dictionary containing taxel array messages
00480   def modifyRobotSpecificTaxels(self, skin_data):
00481     if self.opt.robot == 'pr2':
00482       return self.modifyPR2Taxels(skin_data)
00483     return skin_data # If this is running on a different robot, don't modify the data.
00484 
00485   ## Calls all the sub-component updates
00486   def updateHapticState(self):
00487     self.updateJointStates()
00488     #self.torso_pose = self.updateTorsoPose()
00489     self.updateEndEffectorPose()
00490     self.updateEndEffectorJacobian()
00491     # Skin sensor calculations.
00492     # Get the latest skin data from the skin client
00493     skin_data = self.skin_client.getTrimmedSkinData()
00494     # Trim skin_data based on specific robot state (eg wrist configuration).
00495     skin_data = self.modifyRobotSpecificTaxels(skin_data)
00496     self.updateContactJacobians(skin_data)
00497     # Add the list of  TaxelArray messages to the message
00498     self.skins = skin_data.values()
00499     
00500   ## Build the haptic state message data structure
00501   # @return haptic_state_msg Haptic State message object containing relevant data 
00502   def getHapticStateMessage(self):
00503     # Update all haptic state data (jacobians etc)
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     # TODO Locking on data? - check these are copies.
00512     # Joint states
00513 #    self.updateJointStates()
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 #self.updateTorsoPose()
00522 
00523     # End effector calculations
00524 #    self.updateEndEffectorPose()
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 #    self.updateEndEffectorJacobian()
00529     msg.end_effector_jacobian = self.ma_to_m.matrixListToMultiarray(self.Je)
00530 
00531 #    # Skin sensor calculations.
00532 #    # Get the latest skin data from the skin client
00533 #    skin_data = self.skin_client.getTrimmedSkinData()
00534 #    # Trim skin_data based on specific robot state (eg wrist configuration).
00535 #    skin_data = self.modifyRobotSpecificTaxels(skin_data)
00536 #    # Add the list of  TaxelArray messages to the message
00537 #    msg.skins = skin_data.values()
00538 #    self.updateContactJacobians(skin_data)
00539 # Add the list of  TaxelArray messages to the message
00540     msg.skins = self.skins
00541     msg.contact_jacobians = self.ma_to_m.matrixListToMultiarray(self.Jc)
00542     
00543     return msg
00544   
00545   ## Build and publish the haptic state message.
00546   def publishRobotState(self):
00547     msg = self.getHapticStateMessage()
00548 
00549     # Publish the newly formed state message
00550     for i in range(len(msg.joint_names)):
00551         msg.joint_names[i] = str(msg.joint_names[i]) #testing
00552     self.state_pub.publish(msg)
00553 
00554     # Publish gripper pose for debug purposes
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   ## Handler for Ctrl-C signals. Some of the ROS spin loops don't respond well to
00566   # Ctrl-C without this. 
00567   def signal_handler(self, signal, frame):
00568     print 'Ctrl+C pressed - exiting'
00569     sys.exit(0)
00570 
00571   ## Start the state publisher
00572   def start(self):
00573     signal.signal(signal.SIGINT, self.signal_handler) # Catch Ctrl-Cs
00574     
00575     rospy.loginfo("RobotHapticState: Starting Robot Haptic State publisher")
00576     rate = rospy.Rate(self.rate) # 100Hz, nominally.
00577 
00578     # Blocking sleep to prevent the node publishing until joint states
00579     # are read by the robot client.
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 #      rospy.spin() # Blocking spin for debug/dev purposes
00598       rate.sleep()
00599 
00600 
00601 if __name__ == "__main__":
00602   # Parse an options list specifying robot type
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()


hrl_haptic_mpc
Author(s): Jeff Hawke, Phillip Grice, Marc Killpack, Advait Jain. Advisor and Co-author: Prof. Charlie Kemp. Healthcare Robotics Lab, Georgia Tech
autogenerated on Wed Nov 27 2013 12:27:09