Rose-Hulman Robotics Team

Changeset 420

Show
Ignore:
Timestamp:
02/20/09 17:44:27 (3 years ago)
Author:
spenceal
Message:

adding fancyier drive code, and support for more motor controller commands

Location:
trunk/software/rb
Files:
3 modified

Legend:

Unmodified
Added
Removed
  • trunk/software/rb/controller.py

    r412 r420  
    44class Controller(): 
    55        def __init__(self): 
    6                 self.drive = False 
    7                 self.drive = rb.drive.FakeDrive(rbconfig.left_motor_port, 
    8                                                 rbconfig.right_motor_port) 
    9                 #self.drive = rb.drive.Drive(rbconfig.left_motor_port, 
    10                 #                            rbconfig.right_motor_port) 
     6                #self.drive = rb.drive.FakeDrive(rbconfig.left_motor_port, 
     7                #                               rbconfig.right_motor_port) 
     8                self.drive = rb.drive.Drive(rbconfig.left_motor_port, 
     9                                            rbconfig.right_motor_port) 
  • trunk/software/rb/drive.py

    r419 r420  
    1414# along with this program.  If not, see <http://www.gnu.org/licenses/>. 
    1515 
    16 from __future__ import division, with_statement 
     16from __future__ import division 
    1717 
    1818''' 
     
    2626from serial import Serial 
    2727from thread import start_new_thread 
    28 from threading import RLock 
     28from threading import Lock 
    2929from time import sleep 
    3030 
     
    4545 
    4646Ok, Err = range(2) 
    47 (Tdisable,  Rdisable, 
    48  Tenable,   Renable, 
    49  Tsetdc,    Rsetdc, 
    50  Tgetdc,    Rgetdc, 
    51  Tsetgain,  Rsetgain, 
    52  Tgetgain,  Rgetgain, 
    53  Tsetspeed, Rsetspeed, 
    54  Tgetspeed, Rgetspeed, 
    55  Tgetstat,  Rgetstat, 
    56  Teewrite,  Reewrite) = range(20) 
    57  
     47 
     48messages = { 
     49        'disable' : [{'op':0 , 'fmt':''    }, {'op':1 , 'fmt':''    }], # (nil)                                 
     50        'enable'  : [{'op':2 , 'fmt':''    }, {'op':3 , 'fmt':''    }], # (nil)                                 
     51        'setdc'   : [{'op':4 , 'fmt':'>h'  }, {'op':5 , 'fmt':''    }], # (int16_t dc)                          
     52        'getdc'   : [{'op':6 , 'fmt':''    }, {'op':7 , 'fmt':'>h'  }], # (int16_t dc)                          
     53        'setgain' : [{'op':8 , 'fmt':'>hhh'}, {'op':9 , 'fmt':''    }], # (int16_t Kp, int16_t Ki, int16_t Kd)  
     54        'getgain' : [{'op':10, 'fmt':''    }, {'op':11, 'fmt':'>hhh'}], # (int16_t Kp, int16_t Ki, int16_t Kd)  
     55        'setspeed': [{'op':12, 'fmt':'>h'  }, {'op':13, 'fmt':''    }], # (int16_t rpm)                         
     56        'getspeed': [{'op':14, 'fmt':''    }, {'op':15, 'fmt':'>h'  }], # (int16_t speed)                        
     57        'getstat' : [{'op':16, 'fmt':''    }, {'op':17, 'fmt':'>hhh'}], # (int16_t p, int16_t i, int16_t d)     
     58        'eewrite' : [{'op':18, 'fmt':''    }, {'op':19, 'fmt':''    }], # (nil)                                 
     59} 
    5860 
    5961 
     
    7375                self.left  = Motor(ldev) 
    7476                self.right = Motor(rdev) 
    75                 self.set_speeds(0.0, 0.0) 
     77                self.setspeed(0.0, 0.0) 
    7678         
    7779        def _get_running(self): 
     
    8385         
    8486        running = property(_get_running, _set_running) 
    85          
    86         def set_speeds(self, left, right): 
     87 
     88        def _split(self, type, lt_data, rt_data): 
     89                ''' 
     90                Call _send on the left and right motor passing in type and the 
     91                corresponding data. If data is None, it will not be set 
     92                ''' 
     93                if lt_data == None: 
     94                        l = None 
     95                else: 
     96                        l = self.left._send(type,  *lt_data) 
     97                if rt_data == None: 
     98                        r = None 
     99                else: 
     100                        r = self.right._send(type,  *rt_data) 
     101                return (l, r) 
     102         
     103        def setspeed(self, left, right): 
    87104                ''' 
    88105                Set the motor speeds directly.  `left` and `right` are floats 
     
    94111                for each, respectively. 
    95112                ''' 
    96                 #print "Drive.set_speeds: %f, %f" % (left, right) 
    97                 self.left.target  = clip(left,  -1.0, 1.0) 
    98                 self.right.target = clip(right, -1.0, 1.0) 
     113                print "Drive.setspeed: %f, %f" % (left, right) 
     114                self.left.target  = clip(left,  -1.0, 1.0)*MAX 
     115                self.right.target = clip(right, -1.0, 1.0)*MAX 
     116 
     117        def getspeed(self): 
     118                return (float(self.left._send( "getspeed")) / MAX, 
     119                        float(self.right._send("getspeed")) / MAX) 
     120 
     121        def disable(self):     return self._split("disable", (), ()) 
     122        def enable (self):     return self._split("enable" , (), ()) 
     123        def setdc  (self,l,r): return self._split("setdc"  , l,  r ) 
     124        def getdc  (self):     return self._split("getdc"  , (), ()) 
     125        def setgain(self,l,r): return self._split("setgain", l,  r ) 
     126        def getgain(self):     return self._split("getgain", (), ()) 
     127        def getstat(self):     return self._split("getstat", (), ()) 
     128        def eewrite(self):     return self._split("eewrite", (), ()) 
    99129 
    100130 
     
    105135         
    106136        def __init__(self, port): 
    107                 self.target = 0 
    108                 self.running = True 
    109                 self.current = 0 # Current value reported by the motors 
    110                 self._current_set = 0 # Current value the motors have been set to 
    111                 self._port = Serial(port, 19200, timeout=.5) 
    112                 self.lock = RLock() 
     137                self.running    = True 
     138                self.target     = 0 # Speed the motor coltrollers should be at 
     139                self._port      = Serial(port, 19200, timeout=.5) 
     140                #self._port      = open("/tmp/fake", "w+") 
     141                self._port_lock = Lock() 
    113142                start_new_thread(self._main, ()) 
    114          
     143 
    115144        def _main(self): 
    116                 #print "Motor._main: starting" 
    117                 self.running = True 
    118145                while self.running: 
    119                         #print "Motor._main: stepping" 
    120                         try: 
    121                                 self.step() 
    122                         except Exception, e: 
    123                                 log_error('Motor: Exception in step() %r' % e) 
     146                        cur = self._send("getspeed") 
     147                        if cur: 
     148                                inc = min(0.05*MAX, abs(self.target - cur)) 
     149                                if cur < self.target: 
     150                                        self._send("setspeed", cur + inc) 
     151                                elif cur > self.target: 
     152                                        self._send("setspeed", cur - inc) 
     153                                else: 
     154                                        self._send("setspeed", cur) # Ping! 
    124155                        sleep(.1) 
    125                 self._set_speed(0) 
    126                 #print "Motor._main: exiting" 
    127          
    128         def step(self): 
    129                 with self.lock: 
    130                         inc = min(0.05, abs(self.target - self._current_set)) 
    131                         if self._current_set < self.target: 
    132                                 self._current_set += inc 
    133                         elif self._current_set > self.target: 
    134                                 self._current_set -= inc 
    135                          
    136                         self._set_speed(self._current_set) 
    137                         #~ self.current = (self._get_speed() / MAX) 
    138          
    139         def _send(self, type, msg): 
    140                 #print 'Motor._send: start' 
    141                 self._port.write(chr(type)) 
    142                 self._port.write(chr(len(msg))) 
    143                 self._port.write(msg) 
    144                 #print 'Motor._send: end' 
    145          
    146         def _receive(self): 
    147                 type   = self._port.read(1) 
    148                 length = self._port.read(1) 
    149  
    150                 if len(type)   != 1: 
    151                         print "Timeout reading `type'   from motor controller" 
    152                 if len(length) != 1: 
    153                         print "Timeout reading `length' from motor controller" 
    154  
    155                 if ord(length) == 0: 
    156                         return ord(type), '' 
    157                 else:  
    158                         return ord(type), self._port.read(ord(length)) 
    159          
    160         def _set_speed(self, fspeed): 
    161                 with self.lock: 
    162                         speed = int(fspeed * MAX) 
    163                         #print 'Motor._set_speed: %d' % speed 
    164                         self._send(Tsetspeed, struct.pack('>h', speed)) 
    165                         type, res = self._receive() 
    166                 if type != Rsetspeed or ord(res) != Ok: 
    167                         log_error('motor: Error setting speed') 
    168          
    169         def _set_gain(self, kp, ki, kd): 
    170                 with self.lock: 
    171                         self._send(Tsetgain, struct.pack('>hhh', kp, ki, kd)) 
    172                         type, res = self._receive() 
    173                 if type != Rsetgain or ord(res) != Ok: 
    174                         log_error('motor: Error setting gain') 
    175          
    176         def _write_eeprom(self): 
    177                 with self.lock: 
    178                         self._send(Teewrite, '') 
    179                         type, res = self._receive() 
    180                         if type != Reewrite or ord(res) != Ok: 
    181                                 log_error('motor: Error writing settings to eeprom') 
    182          
    183         def _get_speed(self): 
    184                 with self.lock: 
    185                         self._send(Tgetspeed, '') 
    186                         type, s = self._receive() 
    187                         if type != Rgetspeed: 
    188                                 log_error('motor: Tag mismatch') 
    189                 (speed,) = struct.unpack('>h', s) 
    190                 # speed returned is unscaled, this assumes 50Hz loop 
    191                 return speed * 60.0 * 50 / 256.0 
     156                self._send("setspeed", 0) 
     157         
     158        def _send(self, type, *t_data): 
     159                self._port_lock.acquire() 
     160 
     161                t, r = messages[type] 
     162 
     163                # Transmit query 
     164                t_st = struct.pack(t['fmt'], *t_data) 
     165                self._port.write(chr(t['op'])) 
     166                self._port.write(chr(len(t_st))) 
     167                self._port.write(t_st) 
     168                 
     169                # Recieve response 
     170                r_op = self._port.read(1) 
     171                if len(r_op) != 1: 
     172                        print "Motor._send: Timeout reading `r_type' from motor controller" 
     173                elif r_op != chr(r['op']): 
     174                        print "Motor._send: Recieved incorrect `r_type' from motor controller" 
     175 
     176                r_length = self._port.read(1) 
     177                if len(r_length) != 1: 
     178                        print "Motor._send: Timeout reading `r_length' from motor controller" 
     179                        return 
     180                r_length = ord(r_length) 
     181                if r_length != struct.calcsize(r['fmt']): 
     182                        print "Motor._send: Recieved incorrect `r_length' from motor controller" 
     183 
     184                if r_length == 0: 
     185                        # No need to recieve/unpack structure 
     186                        return 
     187                 
     188                r_st = self._port.read(r_length) 
     189                if len(r_st) != r_length: 
     190                        print "Motor._send: Timeout reading `r_data' from motor controller" 
     191                r_data = struct.unpack(r['fmt'], r_st) 
     192 
     193                if (len(r_data) == 1): 
     194                        # struct's return format is annoying 
     195                        return r_data(0) 
     196 
     197                self._port_lock.release() 
     198                return r_data 
    192199 
    193200 
     
    202209                self.right = FakeMotor() 
    203210         
    204         def set_speeds(self, left, right): 
     211        def setspeed(self, left, right): 
    205212                log_debug("MockDrive: left  motor speed % 3.03f" % left) 
    206213                log_debug("MockDrive: right motor speed % 3.03f" % right) 
     
    212219        def __init__(self, *args, **kwargs): 
    213220                self.target = 0 
    214          
    215         current = property(lambda s: s.target) 
     221        def _send(type, *t_data): 
     222                print "sending %s - %s" % (type, repr(t_data)) 
  • trunk/software/rb/shell.py

    r413 r420  
    114114         
    115115        # Motor control 
     116        def do_setspeed(self, cmd): 
     117                try: 
     118                        lspeed, rspeed = unpack(cmd, (0.0, float), (0.0, float)) 
     119                        self.drive.setspeed(lspeed, rspeed) 
     120                except ValueError: 
     121                        print "Invalid parameters" 
     122 
     123        def do_getspeed(self, cmd): 
     124                self.drive.getspeed() 
     125 
    116126        def do_setgain(self, cmd): 
    117127                try: 
    118128                        kp, ki, kd, m = unpack(cmd, (0, int), (0, int), (0, int), ('b', str)) 
    119                         if m in ('l', 'b'): 
    120                                 self.drive.left._set_gain(kp, ki, kd) 
    121                         if m in ('r', 'b'): 
    122                                 self.drive.right._set_gain(kp, ki, kd) 
     129                        if   m == 'l': 
     130                                self.drive.setgain((kp,ki,kd),None) 
     131                        elif m == 'r': 
     132                                self.drive.setgain(None,(kp,ki,kd)) 
     133                        else: 
     134                                self.drive.setgain((kp,ki,kd),(kp,ki,kd)) 
    123135                except ValueError: 
    124136                        print "Invalid Parameters" 
    125                          
     137 
    126138        def do_getspeed(self, cmd): 
    127                 try: 
    128                         (m,) = unpack(cmd, ('b', str)) 
    129                         print 'm = %r' % m 
    130                         if m in ('l', 'b'): 
    131                                 speed = self.drive.left._get_speed() 
    132                                 print 'l: %d\n' % speed 
    133                         if m in ('r', 'b'): 
    134                                 speed = self.drive.right._get_speed() 
    135                                 print 'r: %d\n' % speed 
    136  
    137                 except ValueError: 
    138                         print "Invalid Parameters" 
    139  
    140  
    141         def do_speeds(self, cmd): 
    142                 try: 
    143                         lspeed, rspeed = unpack(cmd, (0.0, float), (0.0, float)) 
    144                         self.drive.set_speeds(lspeed, rspeed) 
    145                 except ValueError: 
    146                         print "Invalid parameters" 
     139                print self.drive.getspeed() 
     140 
     141        def do_setdc(self, cmd): 
     142                ldc, rdc = unpack(cmd, (0, int), (0, int)) 
     143                print self.drive.setdc(ldc, rdc) 
     144 
     145        def do_disable(self, cmd): 
     146                print self.drive.disable() 
     147 
     148        def do_enable(self, cmd): 
     149                print self.drive.enable() 
     150 
     151        def do_getdc(self, cmd): 
     152                print self.drive.getdc() 
     153 
     154        def do_getgain(self, cmd): 
     155                print self.drive.getgain() 
     156 
     157        def do_getstat(self, cmd): 
     158                print self.drive.getstat() 
     159 
     160        def do_eewrite(self, cmd): 
     161                print self.drive.eewrite() 
    147162         
    148163        def do_stop(self, cmd):