Go to the documentation of this file.00001
00002
00003 import sys
00004 import argparse
00005 import numpy as np
00006
00007 import rospy
00008 from sensor_msgs.msg import JointState
00009 from std_msgs.msg import Float32MultiArray, Float32
00010
00011 from grasp_synergy import GraspSynergy
00012
00013 """
00014
00015 This is the synergy ROS node. It deals with receiving grasp synergy commands
00016 (scalars or arrays), computes the resulting grasp, and commands it to the hand.
00017
00018 For the actual details of the implementation, see grasp_synergy.py.
00019
00020 Author: Felix Duvallet <felixd@gmail.com>
00021
00022 """
00023
00024
00025 class GraspSynergyNode(object):
00026 """
00027 The grasp synergy node subscribes to low-dimensional synergies
00028 and publishes desired joint state.
00029
00030 It is hand agnostic.
00031 """
00032
00033 def __init__(self, joint_cmd_topic,
00034 synergy_input_topic='grasp_synergy',
00035 num_synergies=2):
00036
00037 self._synergy = GraspSynergy()
00038
00039 self._publisher = rospy.Publisher(
00040 joint_cmd_topic, JointState, queue_size=1)
00041
00042 self._subscriber_main = None
00043 self._subscriber_components = []
00044 queue_size = 1
00045 self._init_subscribers(synergy_input_topic, num_synergies, queue_size)
00046
00047 def fit_joint_values(self, joint_values):
00048 return self._synergy.fit_joint_values(joint_values)
00049
00050 def fit_joint_state_messages(self, joint_state_messages):
00051 return self._synergy.fit_joint_state_messages(joint_state_messages)
00052
00053 def fit_bag_file(self, bag_filepath):
00054 return self._synergy.fit_bag_file(bag_filepath)
00055
00056 def command_synergy(self, synergy):
00057
00058 if not self._synergy.trained:
00059 rospy.logwarn('Synergy is not initialized: did you provide '
00060 'training data?')
00061 return
00062
00063 grasp = self._synergy.compute_grasp(synergy)
00064 rospy.logdebug('Commanding synergy: {} -> grasp {}'.format(
00065 synergy, grasp))
00066
00067 joint_state = JointState()
00068 joint_state.position = grasp
00069 self._publisher.publish(joint_state)
00070
00071 def _callback_main(self, data):
00072 """
00073 Main callback for a fully-specified coefficient vector.
00074 Commands the synergy.
00075 """
00076 alpha = data.data
00077 self.command_synergy(alpha)
00078
00079 def _callback_component(self, data, component_number):
00080 """
00081 Component callback (component number & value).
00082
00083 Creates an alpha vector with all zeros except for the given component,
00084 then commands the synergy.
00085 """
00086 rospy.logdebug('Received data for component {} - {}'.format(
00087 component_number, data.data))
00088 alpha = np.zeros((component_number + 1,))
00089 alpha[component_number] = data.data
00090 self.command_synergy(alpha)
00091
00092 def _init_subscribers(self, synergy_input_topic, num_synergies=0,
00093 queue_size=1):
00094 """
00095 Create num_synergies+1 subscribers. The main (top-level) subscriber
00096 listens for an array of floats.
00097
00098 Each component subscriber only listens to the float corresponding to
00099 its component's singular value. Each component subscriber is nested
00100 under the top-level one: synergy_input_topic/
00101
00102 :param synergy_input_topic The top-level topic.
00103
00104 :param num_synergies Number of component subscribers to generate.
00105
00106 :param queue_size Subscriber queue size. Setting the queue size
00107 small allows dropping older messages when a new one is received,
00108 to prevent a large queue of messages to process. This is useful
00109 because the synergy callback can take some time to compute the
00110 grasp.
00111
00112 """
00113
00114
00115 self._subscriber_main = rospy.Subscriber(
00116 synergy_input_topic, Float32MultiArray, self._callback_main,
00117 queue_size=queue_size)
00118 rospy.loginfo('Created main subscriber {}'.format(synergy_input_topic))
00119
00120
00121
00122 for idx in range(num_synergies):
00123 topic = '{}/syn_{}'.format(synergy_input_topic, idx)
00124
00125 subscriber = rospy.Subscriber(
00126 topic, Float32, self._callback_component, idx,
00127 queue_size=queue_size)
00128 self._subscriber_components.append(subscriber)
00129 rospy.loginfo(' Created component subscriber {}'.format(topic))
00130 pass
00131
00132
00133 def run(arguments):
00134 parser = argparse.ArgumentParser(
00135 description='Command hands in a low-dimensional grasp synergy space.')
00136 parser.add_argument('--hand_control_topic', required=True,
00137 help='Commanded joint state topic.')
00138 parser.add_argument('--bag_filename', required=True,
00139 help='Filepath for bag file of grasp data')
00140 parser.add_argument('--num_synergies', default=4,
00141 type=int,
00142 help='Number of synergies.')
00143 args = parser.parse_args(rospy.myargv(arguments))
00144
00145 rospy.init_node('grasp_synergy')
00146
00147 hand_control_topic = args.hand_control_topic
00148 num_synergies = args.num_synergies
00149 fpath = args.bag_filename
00150
00151 node = GraspSynergyNode(joint_cmd_topic=hand_control_topic,
00152 num_synergies=num_synergies)
00153 if not node.fit_bag_file(fpath):
00154 return
00155 rospy.spin()
00156
00157
00158 if __name__ == '__main__':
00159 arguments = sys.argv[1:]
00160 run(arguments)