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
00028
00029
00030
00031
00032
00033
00034
00035
00036 __author__ = 'Antons Rebguns'
00037 __copyright__ = 'Copyright (c) 2010-2011 Antons Rebguns'
00038 __credits__ = 'Cody Jorgensen, Cara Slutter'
00039
00040 __license__ = 'BSD'
00041 __maintainer__ = 'Antons Rebguns'
00042 __email__ = 'anton@email.arizona.edu'
00043
00044
00045 import sys
00046 import errno
00047 from threading import Lock
00048 from threading import Thread
00049 from Queue import Queue
00050
00051 import roslib
00052 roslib.load_manifest('dynamixel_driver')
00053
00054 import rospy
00055 import dynamixel_io
00056 from dynamixel_driver.dynamixel_const import DXL_MODEL_TO_NAME
00057 from dynamixel_driver.dynamixel_const import DXL_MODEL_TO_TORQUE
00058 from dynamixel_driver.dynamixel_const import DXL_MODEL_TO_MAX_VELOCITY
00059
00060 from dynamixel_msgs.msg import MotorState
00061 from dynamixel_msgs.msg import MotorStateList
00062
00063 class SerialProxy():
00064 def __init__(self, port_name='/dev/ttyUSB0', baud_rate='1000000', min_motor_id=1, max_motor_id=25, update_rate=5):
00065 self.port_name = port_name
00066 self.port_namespace = port_name[port_name.rfind('/') + 1:]
00067 self.baud_rate = baud_rate
00068 self.min_motor_id = min_motor_id
00069 self.max_motor_id = max_motor_id
00070 self.update_rate = update_rate
00071
00072 self.__packet_queue = Queue()
00073 self.__state_lock = Lock()
00074
00075 self.motor_states_pub = rospy.Publisher('motor_states/%s' % self.port_namespace, MotorStateList)
00076
00077 def connect(self):
00078 try:
00079 self.__serial_bus = dynamixel_io.DynamixelIO(self.port_name, self.baud_rate)
00080 self.__find_motors()
00081 except dynamixel_io.SerialOpenError, e:
00082 rospy.logfatal(e.message)
00083 sys.exit(1)
00084
00085 self.running = True
00086 Thread(target=self.__process_packet_queue).start()
00087 if self.update_rate > 0: Thread(target=self.__update_motor_states).start()
00088
00089 def disconnect(self):
00090 self.running = False
00091 self.queue_new_packet('shutdown')
00092
00093 def queue_new_packet(self, packet):
00094 self.__packet_queue.put_nowait(packet)
00095
00096 def __find_motors(self):
00097 rospy.loginfo('Pinging motor IDs %d through %d...' % (self.min_motor_id, self.max_motor_id))
00098 self.motors = []
00099
00100 try:
00101 for i in xrange(self.min_motor_id, self.max_motor_id + 1):
00102 result = self.__serial_bus.ping(i)
00103 if result: self.motors.append(i)
00104
00105 if self.motors:
00106 rospy.loginfo('Found motors with IDs: %s.' % str(self.motors))
00107 else:
00108 rospy.logfatal('No motors found, aborting.')
00109 sys.exit(1)
00110
00111 rospy.set_param('dynamixel/%s/connected_ids' % self.port_namespace, self.motors)
00112
00113 counts = {10: 0, 12: 0, 18: 0, 24: 0, 28: 0, 29: 0, 64: 0, 107: 0, 113: 0, 116: 0, 117: 0}
00114
00115 for i in self.motors:
00116 model_number = self.__serial_bus.get_model_number(i)
00117 counts[model_number] += 1
00118 angles = self.__serial_bus.get_angle_limits(i)
00119 voltage = self.__serial_bus.get_voltage(i)
00120
00121 rospy.set_param('dynamixel/%s/%d/model' %(self.port_namespace, i), DXL_MODEL_TO_NAME[model_number])
00122 rospy.set_param('dynamixel/%s/%d/model_number' %(self.port_namespace, i), model_number)
00123 rospy.set_param('dynamixel/%s/%d/torque_per_volt' %(self.port_namespace, i), DXL_MODEL_TO_TORQUE[model_number])
00124 rospy.set_param('dynamixel/%s/%d/max_torque' %(self.port_namespace, i), DXL_MODEL_TO_TORQUE[model_number] * voltage)
00125
00126
00127 rospy.set_param('dynamixel/%s/%d/velocity_per_volt' %(self.port_namespace, i), DXL_MODEL_TO_MAX_VELOCITY[model_number])
00128 rospy.set_param('dynamixel/%s/%d/max_velocity' %(self.port_namespace, i), DXL_MODEL_TO_MAX_VELOCITY[model_number] * voltage)
00129 rospy.set_param('dynamixel/%s/%d/radians_second_per_encoder_tick' %(self.port_namespace, i), DXL_MODEL_TO_MAX_VELOCITY[model_number] * voltage / 1023)
00130
00131 if model_number == 29:
00132 rospy.set_param('dynamixel/%s/%d/encoder_resolution' %(self.port_namespace, i), 4096)
00133 rospy.set_param('dynamixel/%s/%d/range_degrees' %(self.port_namespace, i), 360.00)
00134 rospy.set_param('dynamixel/%s/%d/range_radians' %(self.port_namespace, i), 6.283185307)
00135 rospy.set_param('dynamixel/%s/%d/encoder_ticks_per_degree' %(self.port_namespace, i), 11.377777778)
00136 rospy.set_param('dynamixel/%s/%d/encoder_ticks_per_radian' %(self.port_namespace, i), 651.898646923)
00137 rospy.set_param('dynamixel/%s/%d/degrees_per_encoder_tick' %(self.port_namespace, i), 0.087890625)
00138 rospy.set_param('dynamixel/%s/%d/radians_per_encoder_tick' %(self.port_namespace, i), 0.001533981)
00139 elif model_number == 107:
00140 rospy.set_param('dynamixel/%s/%d/encoder_resolution' %(self.port_namespace, i), 4096)
00141 rospy.set_param('dynamixel/%s/%d/range_degrees' %(self.port_namespace, i), 250.92)
00142 rospy.set_param('dynamixel/%s/%d/range_radians' %(self.port_namespace, i), 4.379380160)
00143 rospy.set_param('dynamixel/%s/%d/encoder_ticks_per_degree' %(self.port_namespace, i), 16.323927945)
00144 rospy.set_param('dynamixel/%s/%d/encoder_ticks_per_radian' %(self.port_namespace, i), 935.292176142)
00145 rospy.set_param('dynamixel/%s/%d/degrees_per_encoder_tick' %(self.port_namespace, i), 0.061259766)
00146 rospy.set_param('dynamixel/%s/%d/radians_per_encoder_tick' %(self.port_namespace, i), 0.001069185)
00147 else:
00148 rospy.set_param('dynamixel/%s/%d/encoder_resolution' %(self.port_namespace, i), 1024)
00149 rospy.set_param('dynamixel/%s/%d/range_degrees' %(self.port_namespace, i), 300.00)
00150 rospy.set_param('dynamixel/%s/%d/range_radians' %(self.port_namespace, i), 5.235987757)
00151 rospy.set_param('dynamixel/%s/%d/encoder_ticks_per_degree' %(self.port_namespace, i), 3.413333333)
00152 rospy.set_param('dynamixel/%s/%d/encoder_ticks_per_radian' %(self.port_namespace, i), 195.569594071)
00153 rospy.set_param('dynamixel/%s/%d/degrees_per_encoder_tick' %(self.port_namespace, i), 0.292968750)
00154 rospy.set_param('dynamixel/%s/%d/radians_per_encoder_tick' %(self.port_namespace, i), 0.005113269)
00155
00156 rospy.set_param('dynamixel/%s/%d/model_number' %(self.port_namespace, i), model_number)
00157 rospy.set_param('dynamixel/%s/%d/min_angle' %(self.port_namespace, i), angles['min'])
00158 rospy.set_param('dynamixel/%s/%d/max_angle' %(self.port_namespace, i), angles['max'])
00159
00160 status_str = 'There are '
00161 for (k, v) in counts.items():
00162 if v: status_str += '%d %s, ' % (v, DXL_MODEL_TO_NAME[k])
00163
00164 rospy.loginfo('%s servos connected' % status_str[:-2])
00165 rospy.loginfo('Dynamixel Manager on port %s initialized' % self.port_name)
00166 except dynamixel_io.FatalErrorCodeError, fece:
00167 rospy.logfatal(fece)
00168 signal_shutdown(fece)
00169 except dynamixel_io.NonfatalErrorCodeError, nfece:
00170 rospy.logwarn(nfece)
00171 except dynamixel_io.ChecksumError, cse:
00172 rospy.logwarn(cse)
00173 except dynamixel_io.DroppedPacketError, dpe:
00174 rospy.loginfo(dpe.message)
00175
00176 def __process_packet_queue(self):
00177 while self.running:
00178
00179 packet = self.__packet_queue.get(True)
00180 if packet == 'shutdown': return
00181 self.__state_lock.acquire()
00182 try:
00183 self.__serial_bus.write_packet(packet)
00184 except dynamixel_io.FatalErrorCodeError, fece:
00185 rospy.logfatal(fece)
00186 signal_shutdown(fece)
00187 except dynamixel_io.NonfatalErrorCodeError, nfece:
00188 rospy.logdebug(nfece)
00189 except dynamixel_io.ChecksumError, cse:
00190 rospy.logdebug(cse)
00191 except dynamixel_io.DroppedPacketError, dpe:
00192 rospy.logdebug(dpe.message)
00193 finally:
00194 self.__state_lock.release()
00195
00196 def __update_motor_states(self):
00197 rate = rospy.Rate(self.update_rate)
00198 while self.running:
00199 self.__state_lock.acquire()
00200
00201 motor_states = []
00202 for i in self.motors:
00203 try:
00204 state = self.__serial_bus.get_feedback(i)
00205 if state:
00206 motor_states.append(MotorState(**state))
00207 if dynamixel_io.exception: raise dynamixel_io.exception
00208 except dynamixel_io.FatalErrorCodeError, fece:
00209 rospy.logfatal(fece)
00210 rospy.signal_shutdown(fece)
00211 except dynamixel_io.NonfatalErrorCodeError, nfece:
00212 rospy.logdebug(nfece)
00213 except dynamixel_io.ChecksumError, cse:
00214 rospy.logdebug(cse)
00215 except dynamixel_io.DroppedPacketError, dpe:
00216 rospy.logdebug(dpe.message)
00217 except OSError, ose:
00218 if ose.errno != errno.EAGAIN:
00219 rospy.logfatal(errno.errorcode[ose.errno])
00220 rospy.signal_shutdown(errno.errorcode[ose.errno])
00221 self.__state_lock.release()
00222
00223 if motor_states:
00224 msl = MotorStateList()
00225 msl.motor_states = motor_states
00226 self.motor_states_pub.publish(msl)
00227
00228 rate.sleep()
00229
00230 if __name__ == '__main__':
00231 try:
00232 serial_proxy = SerialProxy()
00233 serial_proxy.connect()
00234 rospy.spin()
00235 serial_proxy.disconnect()
00236 except rospy.ROSInterruptException: pass
00237