FTSensor.py
Go to the documentation of this file.
00001 #!/usr/bin/python
00002 #
00003 # Copyright (c) 2009, Georgia Tech Research Corporation
00004 # All rights reserved.
00005 #
00006 # Redistribution and use in source and binary forms, with or without
00007 # modification, are permitted provided that the following conditions are met:
00008 #     * Redistributions of source code must retain the above copyright
00009 #       notice, this list of conditions and the following disclaimer.
00010 #     * Redistributions in binary form must reproduce the above copyright
00011 #       notice, this list of conditions and the following disclaimer in the
00012 #       documentation and/or other materials provided with the distribution.
00013 #     * Neither the name of the Georgia Tech Research Corporation nor the
00014 #       names of its contributors may be used to endorse or promote products
00015 #       derived from this software without specific prior written permission.
00016 #
00017 # THIS SOFTWARE IS PROVIDED BY GEORGIA TECH RESEARCH CORPORATION ''AS IS'' AND
00018 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00019 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00020 # DISCLAIMED. IN NO EVENT SHALL GEORGIA TECH BE LIABLE FOR ANY DIRECT, INDIRECT,
00021 # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
00022 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
00023 # OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00024 # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
00025 # OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
00026 # ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00027 #
00028 
00029 #  \author Advait Jain (Healthcare Robotics Lab, Georgia Tech.)
00030 #  \author Cressel Anderson (Healthcare Robotics Lab, Georgia Tech.)
00031 #  \author Hai Nguyen (Healthcare Robotics Lab, Georgia Tech.)
00032 
00033 import time, serial
00034 import serial
00035 
00036 class FTSensor:
00037     """
00038         Instantiate to poll the force/torque sensor of your choice.
00039         Must continually poll, running anything else in the same
00040         process will result in many failed reads and/or incorrect 
00041         values!
00042     """
00043     def __init__(self, dev, baudrate=19200):
00044         print 'FTSensor: opening serial port (baudrate =', baudrate, ')'
00045         self.ftcon = serial.Serial(dev,timeout=0.1)
00046         print 'FTSensor: setting properties'
00047         self.ftcon.setBaudrate(baudrate)
00048         self.ftcon.setParity('N')
00049         self.ftcon.setStopbits(1)
00050         self.ftcon.open()
00051 
00052         #self.RESET_INTERVAL=1.0 #seconds until transmittion is reset to fix bug
00053         count = 0
00054         self.reset_time = None
00055         self.reset()
00056         while not self._start_query():
00057             rospy.logwarn('FTSensor: resetting')
00058             count = count + 1
00059             self.reset()
00060             if count == 10:
00061                 rospy.logfatal('FTSensor.__init__: Too many resets.  Try manually restarting FT sensors.')
00062 
00063         #self.last_access = time.time()
00064         self.last_value = []
00065 
00066     def read(self):
00067         '''
00068             Try to return a fresh reading *always*
00069         '''
00070         current_value = self.last_value
00071         while current_value == self.last_value:
00072             t = self.ftcon.read(19)
00073             #if we get an error message, restart
00074             if len(t) < 1 or ord(t[0]) != 0 or len(t) < 10:
00075                 #pass
00076                 #self.reset()
00077                 print 'exiting due to if len(t) < 1 or ord(t[0]) != 0 or len(t) < 10'
00078                 print 't is', t
00079                 exit()
00080                 while not self._start_query():
00081                     #self.reset()
00082                     print 'exiting due to not self._start_query()'
00083                     print 't is', t
00084                     exit()
00085                 break
00086             else:
00087                 current_value = t
00088                 #current_value = binary_to_ft(t)
00089 
00090         self.last_value = current_value
00091         return current_value
00092 
00093     def read_ft(self):
00094         f = binary_to_ft(self.read())
00095 
00096         if abs(f[0]) > 500.0:
00097             exit()
00098         return f
00099 
00100     #def binary_to_ft( self, raw_binary ):
00101     #    counts_per_force  = 192
00102     #    counts_per_torque = 10560
00103 
00104     #    #raw_binary[0] = error value
00105     #    #TODO: this error is a checksum byte that we should watch for
00106     #    #corrupted transmission
00107     #    Fx = ord(raw_binary[1])*65536+ord(raw_binary[2])*256+ord(raw_binary[3])
00108     #    Fy = ord(raw_binary[4])*65536+ord(raw_binary[5])*256+ord(raw_binary[6])
00109     #    Fz = ord(raw_binary[7])*65536+ord(raw_binary[8])*256+ord(raw_binary[9])
00110     #    Tx = ord(raw_binary[1])*65536+ord(raw_binary[2])*256+ord(raw_binary[3])
00111     #    Ty = ord(raw_binary[4])*65536+ord(raw_binary[5])*256+ord(raw_binary[6])
00112     #    Tz = ord(raw_binary[7])*65536+ord(raw_binary[8])*256+ord(raw_binary[9])
00113     #    
00114     #    _temp_val = []
00115     #    for c,list in zip([counts_per_force, counts_per_torque], [[Fx,Fy,Fz], [Tx,Ty,Tz]]):
00116     #        for val in list:
00117     #            if val > 8388607: #Adjust for two's complement
00118     #                val -= 16777216
00119     #            val /= float(c) #scale so the values are in N and Nm
00120     #            _temp_val.append(val)
00121 
00122     #    Fx = _temp_val[0]
00123     #    Fy = _temp_val[1]
00124     #    Fz = _temp_val[2]
00125     #    Tx = _temp_val[3]
00126     #    Ty = _temp_val[4]
00127     #    Tz = _temp_val[5]
00128 
00129     #    return [Fx,Fy,Fz,Tx,Ty,Tz]
00130 
00131     def _start_query( self ):
00132         self.ftcon.write('QS\r')
00133         t = self.ftcon.read(5) # echo
00134         if 5 == len(t):
00135             st = 'QS: '
00136             for i in range(5):
00137                 st += str(ord(t[i])) + '\t'
00138             return True
00139         else:
00140             return False
00141 
00142 
00143     def _stop_query(self):
00144         self.ftcon.write('\r')
00145         self.ftcon.flushInput()
00146         self.ftcon.flush()
00147         t = self.ftcon.readlines(3) # flush doesnt seem to work
00148         #print t
00149 
00150     def reset(self):
00151         ctime = time.time()
00152         if self.reset_time != None:
00153             if ctime - self.reset_time < 2:
00154                 self.reset_time = ctime
00155                 return
00156         self.reset_time = ctime
00157         print 'FTSensor.reset(): Resetting at time', time.ctime()
00158 
00159         self._stop_query()
00160         self.ftcon.write('CD B\r')
00161         t = self.ftcon.readlines(2) # echo
00162         #print t
00163         self.ftcon.write('SA 16\r')
00164         t = self.ftcon.readlines(2) # echo
00165         #print t
00166         self.ftcon.write('SF\r')
00167         t = self.ftcon.readlines(2) # echo
00168         #print t
00169         self.ftcon.write('CF\r')
00170         t = self.ftcon.readlines(2) # echo
00171         #print t
00172         
00173         # we might should consider using CD R or resolved gauge
00174         self.ftcon.write('CD R\r')
00175         t = self.ftcon.readlines(2) # echo
00176         #print t
00177         self.ftcon.write('CF 1\r')
00178         t = self.ftcon.readlines(2) # echo
00179         #print t
00180         self.ftcon.write('SF\r')
00181         t = self.ftcon.readlines(2) # echo
00182         #print t
00183         self._zero_bias()
00184         self.ftcon.write('SZ\r')
00185         t = self.ftcon.readlines(2) # echo
00186         #print t
00187 
00188         #self.last_reset=time.time()
00189 
00190     def _zero_bias(self):
00191         """Don't use, now biased in software"""
00192         self.ftcon.write('SZ\r')
00193         t = self.ftcon.readlines(4) # echo
00194         #print t
00195 
00196 
00197 def binary_to_ft( raw_binary ):
00198     counts_per_force  = 192
00199     counts_per_torque = 10560
00200 
00201     #raw_binary[0] = error value
00202     #TODO: this error is a checksum byte that we should watch for
00203     #corrupted transmission
00204     Fx = ord(raw_binary[1])*65536+ord(raw_binary[2])*256+ord(raw_binary[3])
00205     Fy = ord(raw_binary[4])*65536+ord(raw_binary[5])*256+ord(raw_binary[6])
00206     Fz = ord(raw_binary[7])*65536+ord(raw_binary[8])*256+ord(raw_binary[9])
00207     Tx = ord(raw_binary[10])*65536+ord(raw_binary[11])*256+ord(raw_binary[12])
00208     Ty = ord(raw_binary[13])*65536+ord(raw_binary[14])*256+ord(raw_binary[15])
00209     Tz = ord(raw_binary[16])*65536+ord(raw_binary[17])*256+ord(raw_binary[18])
00210     
00211     _temp_val = []
00212     for c,list in zip([counts_per_force, counts_per_torque], [[Fx,Fy,Fz], [Tx,Ty,Tz]]):
00213         for val in list:
00214             if val > 8388607: #Adjust for two's complement
00215                 val -= 16777216
00216             val /= float(c) #scale so the values are in N and Nm
00217             _temp_val.append(val)
00218 
00219     Fx = _temp_val[0]
00220     Fy = _temp_val[1]
00221     Fz = -_temp_val[2]
00222     Tx = _temp_val[3]
00223     Ty = _temp_val[4]
00224     Tz = _temp_val[5]
00225 
00226     return [Fx,Fy,Fz,Tx,Ty,Tz]
00227 
00228 
00229 if __name__ == '__main__':
00230     import optparse
00231     p = optparse.OptionParser()
00232     p.add_option('--mode', action='store', default='run', type='string', 
00233                  dest='mode', help='either "test" or "run"')
00234     p.add_option('--name', action='store', default='ft1', type='string', 
00235                  dest='name', help='name of sensor')
00236     p.add_option('--path', action='store', default='/dev/robot/fingerFT1', type = 'string',
00237                  dest='path', help='path to force torque device in (linux)')
00238     p.add_option('--baudrate', action='store', default=19200, type = 'int', 
00239                  dest='baudrate', 
00240                  help='baudrate that force torque boxes are running at (VERY IMPORTANT!)')
00241     opt, args = p.parse_args()
00242     print 'FTSensor: Reading from', opt.path
00243 
00244     if opt.mode == 'run':
00245         import roslib; roslib.load_manifest('force_torque')
00246         import rospy
00247         import hrl_lib.rutils as ru
00248         from force_torque.srv import *
00249         import numpy as np
00250         import time
00251 
00252         node_name = 'FT_poller_' + opt.name
00253         service_name = 'FTRelay_' + opt.name + '_set_ft'
00254 
00255         rospy.init_node(node_name)
00256         print node_name + ': waiting for service', service_name
00257         rospy.wait_for_service(service_name)
00258         ft_server_set_ft = rospy.ServiceProxy(service_name, StringService)
00259         ftsensor = FTSensor(opt.path, baudrate=opt.baudrate)
00260 
00261         times = []
00262         print node_name + ': Retrieving sensor data and sending to FTRelay on service', service_name
00263         #for i in range(2000):
00264         while not rospy.is_shutdown():
00265             v = ftsensor.read()
00266             #print repr(v), v.__class__
00267             
00268             t = rospy.get_time()
00269             #times.append(time.time())
00270             try:
00271                 ft_server_set_ft(v, t)
00272             except rospy.ServiceException, e:
00273                 print "Service call failed %s" % e
00274 
00275         print 'rospy is not shutdown', not rospy.is_shutdown()
00276         #a = np.array(times)
00277         #diffs = a[1:] - a[:-1]
00278         #print 1.0/diffs.mean(), 1.0/np.std(diffs)
00279         #pl.plot(diffs, '.') 
00280         #pl.show()
00281 
00282     if opt.mode == 'test':
00283         print 'testing...'
00284         import numpy as np
00285         #import pylab as pl
00286 
00287         print 'Testing', opt.path
00288         sensor1 = FTSensor(opt.path, opt.baudrate)
00289 
00290         tlist = []
00291         for i in range(200):
00292             t0 = time.time()
00293             v1 = sensor1.read_ft()
00294             t1 = time.time()
00295             tlist.append(t1 - t0)
00296             print np.linalg.norm(v1)
00297 
00298         #pl.plot(tlist)
00299         #pl.show()
00300 


force_torque
Author(s): Advait Jain, Cressel Anderson, Hai Nguyen, Advisor: Prof. Charlie Kemp, Lab: Healthcare Robotics Lab at Georgia Tech
autogenerated on Wed Nov 27 2013 11:58:12