Rose-Hulman Robotics Team

Changeset 445

Show
Ignore:
Timestamp:
03/07/09 02:48:26 (3 years ago)
Author:
mosttw
Message:

Added data logging re #48; added Wiimote control to GUI

Location:
trunk/software
Files:
1 added
10 modified

Legend:

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

    r377 r445  
    2323from math import pi 
    2424 
    25 from cwiid import (Wiimote, LED1_ON, LED2_ON, LED3_ON, LED4_ON, BTN_A, 
    26                                          FLAG_MESG_IFC, RPT_BTN, RPT_STATUS, RPT_NUNCHUK, 
    27                                          MESG_ERROR, MESG_NUNCHUK, MESG_BTN, 
    28                                          ERROR_DISCONNECT, ERROR_COMM) 
    2925 
    3026from rb.core.logging import log_debug, log_info, log_warn, log_error, log_die 
     
    4339TARGET_POINT = (39.4843167, -87.3222833) 
    4440 
    45 ''' 
    46 The zero point of the Wiimote nunchuk. 
    47 ''' 
    48 STICK_CENTER = (124, 136) 
    4941 
    5042 
     
    9991                        self.stop_wiimote() 
    10092         
     93        def stop(self): 
     94                self.running = False 
     95         
    10196        def init_sensors(self): 
    10297                self.gps = GPS(rbconfig.gps_port) 
     
    115110                self.drive.running = False 
    116111         
    117         def init_wiimote(self): 
    118                 ''' 
    119                 Initialize the Wiimote.  This needs to be done here because 
    120                 cwiid doesn't line running in anything other than the main 
    121                 thread. 
    122                 ''' 
    123                 for i in range(10): 
    124                         try: 
    125                                 log_info("auto: Connecting to the Wiimote: Press 1+2") 
    126                                 self.wiimote = Wiimote(rbconfig.wiimote_addr) 
    127                         except RuntimeError: 
    128                                 pass 
    129                         else: 
    130                                 log_info("auto: Connected to the Wiimote") 
    131                                 break 
    132                  
    133                 if self.wiimote is None: 
    134                         log_die("auto: Unable to contact the wiimote") 
    135                         sys.exit(1) 
    136                  
    137                 # Signal that the connection has been made 
    138                 self.wiimote.rumble = True 
    139                 time.sleep(.25) 
    140                 self.wiimote.rumble = False 
    141                 self.wiimote.rpt_mode = RPT_BTN | RPT_STATUS | RPT_NUNCHUK 
    142                  
    143                 self.wiimote.enable(FLAG_MESG_IFC) 
    144                 self.wiimote.mesg_callback = self.wiimote_mesg 
    145112         
    146         def stop_wiimote(self): 
    147                 self.wiimote.close() 
    148                 self.wiimote = None 
    149          
    150         def wiimote_control(self): 
    151                 ''' 
    152                 Set the motors based on the Wiimote's Nunchuk's analog stick. 
    153                 ''' 
    154                 x = float(self.stick[0] - STICK_CENTER[0]) 
    155                 y = float(self.stick[1] - STICK_CENTER[1]) 
    156                  
    157                 lspeed = x / 127.0 if (abs(x) > 5) else 0 
    158                 rspeed = y / 127.0 if (abs(y) > 5) else 0 
    159                  
    160                 self.drive.set_speeds(lspeed, rspeed) 
    161          
    162         def wiimote_mesg(self, messages): 
    163                 ''' 
    164                 Handle messages from the Wiimote.  Be careful here, as cwiid 
    165                 swallows exceptions. 
    166                 ''' 
    167                 try: 
    168                         for type, data in messages: 
    169                                 if type == MESG_ERROR: 
    170                                         if data == ERROR_DISCONNECT: 
    171                                                 self.running = False 
    172                                                 log_info("auto: Wiimote disconnected; exiting") 
    173                                         elif data == ERROR_COMM: 
    174                                                 log_info("auto: ERROR_COMM encountered") 
    175                                 elif type == MESG_BTN: 
    176                                         if data & BTN_A: 
    177                                                 self.autonomous = not self.autonomous 
    178                                                 log_info('auto: Toggled autonomous: %s' % self.autonomous) 
    179                                 elif type == MESG_NUNCHUK: 
    180                                         self.stick = data['stick'] 
    181                 except Exception, e: 
    182                         print e 
    183                         self.running = False 
    184113         
    185114        def get_inputs(self): 
     
    248177                                self.wiimote.rumble = False 
    249178         
    250         def set_leds(self): 
    251                 ''' 
    252                 Set Wiimote LEDs based on current status. 
    253                 ''' 
    254                 led = LED1_ON 
    255                 if self.autonomous: 
    256                         led |= LED2_ON 
    257                 if self.accel is not None: 
    258                         led |= LED3_ON 
    259                 if self.coords is not None: 
    260                         led |= LED4_ON 
    261                 if led != self.led: 
    262                         self.led = led 
    263                         self.wiimote.led = led 
    264179 
    265180 
  • trunk/software/rb/controller.py

    r431 r445  
    11import rbconfig 
    22import rb.drive 
     3import rb.gps 
     4import rb.microstrain 
     5import rb.wiimote 
    36 
    4 class Controller(): 
     7class Controller(object): 
    58        def __init__(self): 
    6                 self.mode = None 
    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) 
     9                self.navigator = None 
     10                self.drive = None 
     11                self.gps = None 
     12                self.microstrain = None 
     13                self.wiimote = None 
    1114         
    12         def set_mode(self, mode): 
     15        def set_navigator(self, nav): 
    1316                ''' 
    14                 Set the current mode.  Override this method in a subclass 
    15                 to do something useful. 
     17                Set the current navigator.  Override this method in a subclass 
     18                to do something useful.  Return True on success, else False. 
    1619                ''' 
    17                 self.mode = mode 
     20                self.navigator = nav 
     21                return True 
     22         
     23        def init_drive(self): 
     24                if rbconfig.fake_drive: 
     25                        self.drive = rb.drive.FakeDrive(rbconfig.left_motor_port, 
     26                                                                                        rbconfig.right_motor_port) 
     27                else: 
     28                        self.drive = rb.drive.Drive(rbconfig.left_motor_port, 
     29                                                                                rbconfig.right_motor_port) 
     30         
     31        def init_gps(self): 
     32                self.gps = rb.gps.GPS(rbconfig.gps_port) 
     33         
     34        def init_microstrain(self): 
     35                self.microstrain = rb.microstrain.MicroStrain(rbconfig.microstrain_port) 
     36         
     37        def init_wiimote(self): 
     38                self.wiimote = rb.wiimote.Wiimote(rbconfig.wiimote_addr, self) 
  • trunk/software/rb/gui/compass.py

    r425 r445  
    2020 
    2121import gtk 
     22import cairo 
    2223 
    2324 
     
    5556                context.set_line_width(line_width) 
    5657                context.arc(center_x, center_y, radius, 0, 2 * pi) 
    57                 context.set_source_rgb(1.0, 1.0, 1.0) 
     58                context.set_source_rgba(1.0, 1.0, 1.0, 1.0) 
    5859                context.fill_preserve() 
    5960                context.set_source_rgb(0, 0, 0) 
     
    6869                        context.stroke() 
    6970                 
     71                # Draw a shiny bit 
     72                #gleam = cairo.LinearGradient(center_x, center_y + .2 * radius, 
     73                #                            center_x - .2 * radius, center_y - radius) 
     74                #gleam.add_color_stop_rgba(0.0, 1.0, 1.0, 1.0, 0.0) 
     75                #gleam.add_color_stop_rgba(0.4, 1.0, 1.0, 1.0, 0.3) 
     76                #gleam.add_color_stop_rgba(1.0, 1.0, 1.0, 1.0, 0.1) 
     77                #context.arc(center_x, center_y, radius * .96, pi - .1, 0.0) 
     78                #context.arc_negative(center_x, center_y, radius * .4, .05, pi - .05) 
     79                #context.set_source(gleam) 
     80                #context.fill() 
     81 
    7082                # Draw the bob in the center 
    7183                context.arc(center_x, center_y, max(3, .01 * radius), 0, 2 * pi) 
  • trunk/software/rb/gui/gui.glade

    r430 r445  
    11<?xml version="1.0" encoding="UTF-8" standalone="no"?> 
    22<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd"> 
    3 <!--Generated with glade3 3.4.5 on Wed Feb 25 23:31:38 2009 --> 
     3<!--Generated with glade3 3.4.5 on Sat Mar  7 02:00:15 2009 --> 
    44<glade-interface> 
    55  <widget class="GtkWindow" id="window"> 
     
    134134                        <property name="label" translatable="yes">k_d</property> 
    135135                        <property name="use_underline">True</property> 
    136                         <property name="mnemonic_widget">gain_value_kp</property> 
     136                        <property name="mnemonic_widget">gain_value_kd</property> 
    137137                      </widget> 
    138138                      <packing> 
     
    237237        </child> 
    238238        <child> 
    239           <widget class="GtkHBox" id="mode"> 
     239          <widget class="GtkHBox" id="navigator"> 
    240240            <property name="visible">True</property> 
    241241            <property name="homogeneous">True</property> 
    242242            <child> 
    243               <widget class="GtkRadioButton" id="mode_manual"> 
     243              <widget class="GtkRadioButton" id="nav_manual"> 
    244244                <property name="visible">True</property> 
    245245                <property name="can_focus">True</property> 
     
    247247                <property name="response_id">0</property> 
    248248                <property name="active">True</property> 
    249                 <signal name="toggled" handler="mode_cb"/> 
    250               </widget> 
    251             </child> 
    252             <child> 
    253               <widget class="GtkRadioButton" id="mode_auto"> 
     249                <signal name="toggled" handler="nav_cb"/> 
     250              </widget> 
     251            </child> 
     252            <child> 
     253              <widget class="GtkRadioButton" id="nav_wiimote"> 
     254                <property name="visible">True</property> 
     255                <property name="can_focus">True</property> 
     256                <property name="label" translatable="yes">Wiimote</property> 
     257                <property name="response_id">0</property> 
     258                <property name="active">True</property> 
     259                <property name="group">nav_manual</property> 
     260                <signal name="toggled" handler="nav_cb"/> 
     261              </widget> 
     262              <packing> 
     263                <property name="position">1</property> 
     264              </packing> 
     265            </child> 
     266            <child> 
     267              <widget class="GtkRadioButton" id="nav_auto"> 
    254268                <property name="visible">True</property> 
    255269                <property name="can_focus">True</property> 
     
    257271                <property name="response_id">0</property> 
    258272                <property name="active">True</property> 
    259                 <property name="group">mode_manual</property> 
    260                 <signal name="toggled" handler="mode_cb"/> 
    261               </widget> 
    262               <packing> 
    263                 <property name="position">1</property> 
    264               </packing> 
    265             </child> 
    266             <child> 
    267               <widget class="GtkRadioButton" id="mode_stop"> 
     273                <property name="group">nav_manual</property> 
     274                <signal name="toggled" handler="nav_cb"/> 
     275              </widget> 
     276              <packing> 
     277                <property name="position">2</property> 
     278              </packing> 
     279            </child> 
     280            <child> 
     281              <widget class="GtkRadioButton" id="nav_stop"> 
    268282                <property name="visible">True</property> 
    269283                <property name="can_focus">True</property> 
     
    273287                <property name="response_id">0</property> 
    274288                <property name="active">True</property> 
    275                 <property name="group">mode_manual</property> 
    276                 <signal name="toggled" handler="mode_cb"/> 
    277               </widget> 
    278               <packing> 
    279                 <property name="position">2</property> 
     289                <property name="group">nav_manual</property> 
     290                <signal name="toggled" handler="nav_cb"/> 
     291              </widget> 
     292              <packing> 
     293                <property name="position">3</property> 
    280294              </packing> 
    281295            </child> 
     
    283297          <packing> 
    284298            <property name="position">1</property> 
     299          </packing> 
     300        </child> 
     301        <child> 
     302          <widget class="GtkStatusbar" id="statusbar"> 
     303            <property name="visible">True</property> 
     304            <property name="spacing">2</property> 
     305          </widget> 
     306          <packing> 
     307            <property name="expand">False</property> 
     308            <property name="position">2</property> 
    285309          </packing> 
    286310        </child> 
  • trunk/software/rb/gui/gui.py

    r431 r445  
    33import gtk 
    44 
     5import rbconfig 
    56from rb.core.event   import connect 
    67from rb.core.logging import log_debug, log_info 
     
    910from rb.gui.analog   import AnalogWidget 
    1011from rb.gui.speedgraph import SpeedGraph 
     12from rb.transcript import TranscriptLogger 
    1113 
    1214import os.path 
     
    1416# Full path to the GUI definition file 
    1517GTKBUILDER_FILE = os.path.join(os.path.dirname(__file__), 'gui.xml') 
     18 
     19# Map widget names to navigator names 
     20WIDGET_NAV_MAP = { 
     21        'nav_manual': 'analog', 
     22        'nav_wiimote': 'wiimote', 
     23        'nav_auto': 'autonomous', 
     24        'nav_stop': 'stop', 
     25} 
     26 
    1627 
    1728class GUI(Controller): 
     
    2334                Controller.__init__(self) 
    2435                gobject.threads_init() 
    25  
     36                 
     37                self.init_drive() 
     38                self.init_gps() 
     39                self.init_microstrain() 
     40                self.init_wiimote() 
     41                self.transcript = TranscriptLogger('/tmp/rblog.txt', 
     42                                                        self.drive, self.gps, self.microstrain) 
     43                 
    2644                self.arrow_keys_map = { 
    2745                        gtk.keysyms.Up   : ( 0.01,  0.01), 
     
    3856 
    3957                # Glade-3 -> GtkBuilder fix 
    40                 for btn in ['mode_manual', 'mode_auto', 'mode_stop']: 
     58                for btn in ['nav_manual', 'nav_wiimote', 'nav_auto', 'nav_stop']: 
    4159                        self.builder.get_object(btn).set_mode(False) 
    4260                log_debug("gui: Done creating window") 
     
    5169 
    5270                self.window.show_all() 
    53                 self.set_mode('manual') 
     71                self.set_navigator('analog') 
     72                 
    5473                gtk.main() 
    5574 
    56         def set_mode(self, mode): 
    57                 Controller.set_mode(self, mode) # set the mode attribute 
    58                 # TODO: disable manual motor control when in autonomous mode 
    59                 if mode == 'stop': 
    60                         self.set_speed(0, 0) 
    61                 elif mode == 'autonomous': 
    62                         print "Autonomous mode not yet implemented" 
    63                 elif mode == 'manual': 
    64                         print "Switching to manual mode" 
    65                  
    66                 self.analog.enabled = (mode == 'manual') 
    67                  
     75        def wiimote_connect(self): 
     76                sb = self.builder.get_object('statusbar') 
     77                context_id = sb.get_context_id('wiimote_connect') 
     78                # FIXME: Make the first message show up before we do the blocking start() call 
     79                msg = 'Connecting to the Wiimote at %s' % rbconfig.wiimote_addr 
     80                print msg 
     81                sb.push(context_id, msg) 
     82                try: 
     83                        self.wiimote.start() 
     84                except IOError: 
     85                        success = False 
     86                        msg = 'Wiimote connection failed' 
     87                else: 
     88                        success = True 
     89                        msg = 'Connected to the Wiimote at %s' % rbconfig.wiimote_addr 
     90                sb.pop(context_id) 
     91                message_id = sb.push(context_id, msg) 
     92                gobject.timeout_add(3000, lambda: sb.remove(context_id, message_id)) 
     93                return success 
     94 
     95        def set_navigator(self, nav): 
     96                ''' 
     97                Set the navigator.  Return True if setting it is successful. 
     98                ''' 
     99                try: 
     100                        # We need to try switching to the wiimote navigator first since it can fail 
     101                        if nav == 'wiimote': 
     102                                if not self.wiimote_connect(): 
     103                                        return False 
     104                        elif nav == 'autonomous': 
     105                                print "Autonomous navigator not yet implemented" 
     106                                return False 
     107                         
     108                        if not Controller.set_navigator(self, nav): # set the navigator attribute 
     109                                return False 
     110                         
     111                        if nav == 'stop': 
     112                                print "Switching to 'stop' navigator" 
     113                                self.set_speed(0, 0) 
     114                        elif nav == 'analog': 
     115                                print "Switching to analog navigator" 
     116                        elif nav == 'wiimote': 
     117                                print "Switching to wiimote navigator" 
     118                        return True 
     119                finally: 
     120                        self.analog.enabled = (self.navigator == 'analog') 
     121                        self.update_nav_toggles() 
    68122 
    69123        def key_press_cb(self, widget, event): 
     
    120174                log_debug("gui: Window closed") 
    121175 
    122         def mode_cb(self, widget=None, data=None): 
     176        def nav_cb(self, widget=None, data=None): 
    123177                ''' 
    124                 Callback for mode selection toggle buttons. 
     178                Callback for navigator selection toggle buttons. 
    125179                ''' 
    126                 new_mode = { 
    127                         'mode_stop': 'stop', 
    128                         'mode_manual': 'manual', 
    129                         'mode_auto': 'autonomous', 
    130                 }[widget.get_name()] 
    131                 self.set_mode(new_mode) 
     180                if widget.get_active(): 
     181                        new_nav = WIDGET_NAV_MAP[widget.get_name()] 
     182                        self.set_navigator(new_nav) 
     183         
     184        def update_nav_toggles(self): 
     185                ''' 
     186                Update the nav widgets to reflect the current  
     187                ''' 
     188                for name, nav in WIDGET_NAV_MAP.items(): 
     189                        active = self.navigator == nav 
     190                        self.builder.get_object(name).set_active(active) 
  • trunk/software/rb/gui/gui.xml

    r430 r445  
    11<?xml version="1.0"?> 
    2 <!--Generated with glade3 3.4.5 on Wed Feb 25 23:31:38 2009 --> 
     2<!--Generated with glade3 3.4.5 on Sat Mar  7 02:00:15 2009 --> 
    33<interface> 
    44  <object class="GtkAdjustment" id="adjustment1"> 
     
    152152                        <property name="label" translatable="yes">k_d</property> 
    153153                        <property name="use_underline">True</property> 
    154                         <property name="mnemonic_widget">gain_value_kp</property> 
     154                        <property name="mnemonic_widget">gain_value_kd</property> 
    155155                      </object> 
    156156                      <packing> 
     
    247247        </child> 
    248248        <child> 
    249           <object class="GtkHBox" id="mode"> 
     249          <object class="GtkHBox" id="navigator"> 
    250250            <property name="visible">True</property> 
    251251            <property name="homogeneous">True</property> 
    252252            <child> 
    253               <object class="GtkRadioButton" id="mode_manual"> 
     253              <object class="GtkRadioButton" id="nav_manual"> 
    254254                <property name="visible">True</property> 
    255255                <property name="can_focus">True</property> 
    256256                <property name="label" translatable="yes">Manual</property> 
    257257                <property name="active">True</property> 
    258                 <signal handler="mode_cb" name="toggled"/> 
    259               </object> 
    260             </child> 
    261             <child> 
    262               <object class="GtkRadioButton" id="mode_auto"> 
     258                <signal handler="nav_cb" name="toggled"/> 
     259              </object> 
     260            </child> 
     261            <child> 
     262              <object class="GtkRadioButton" id="nav_wiimote"> 
     263                <property name="visible">True</property> 
     264                <property name="can_focus">True</property> 
     265                <property name="label" translatable="yes">Wiimote</property> 
     266                <property name="active">True</property> 
     267                <property name="group">nav_manual</property> 
     268                <signal handler="nav_cb" name="toggled"/> 
     269              </object> 
     270              <packing> 
     271                <property name="position">1</property> 
     272              </packing> 
     273            </child> 
     274            <child> 
     275              <object class="GtkRadioButton" id="nav_auto"> 
    263276                <property name="visible">True</property> 
    264277                <property name="can_focus">True</property> 
    265278                <property name="label" translatable="yes">Autonomous</property> 
    266279                <property name="active">True</property> 
    267                 <property name="group">mode_manual</property> 
    268                 <signal handler="mode_cb" name="toggled"/> 
    269               </object> 
    270               <packing> 
    271                 <property name="position">1</property> 
    272               </packing> 
    273             </child> 
    274             <child> 
    275               <object class="GtkRadioButton" id="mode_stop"> 
     280                <property name="group">nav_manual</property> 
     281                <signal handler="nav_cb" name="toggled"/> 
     282              </object> 
     283              <packing> 
     284                <property name="position">2</property> 
     285              </packing> 
     286            </child> 
     287            <child> 
     288              <object class="GtkRadioButton" id="nav_stop"> 
    276289                <property name="visible">True</property> 
    277290                <property name="can_focus">True</property> 
     
    280293                <property name="image_position">GTK_POS_TOP</property> 
    281294                <property name="active">True</property> 
    282                 <property name="group">mode_manual</property> 
    283                 <signal handler="mode_cb" name="toggled"/> 
    284               </object> 
    285               <packing> 
    286                 <property name="position">2</property> 
     295                <property name="group">nav_manual</property> 
     296                <signal handler="nav_cb" name="toggled"/> 
     297              </object> 
     298              <packing> 
     299                <property name="position">3</property> 
    287300              </packing> 
    288301            </child> 
     
    290303          <packing> 
    291304            <property name="position">1</property> 
     305          </packing> 
     306        </child> 
     307        <child> 
     308          <object class="GtkStatusbar" id="statusbar"> 
     309            <property name="visible">True</property> 
     310            <property name="spacing">2</property> 
     311          </object> 
     312          <packing> 
     313            <property name="expand">False</property> 
     314            <property name="position">2</property> 
    292315          </packing> 
    293316        </child> 
  • trunk/software/rb/gui/mapwidget.py

    r332 r445  
    2727                'location_clicked': (gobject.SIGNAL_RUN_FIRST, 
    2828                                                        gobject.TYPE_NONE, 
    29                                                         (gobject.TYPE_DOUBLE, gobject.TYPE_DOUBLE)) 
     29                                                        (object,)) 
    3030        } 
    3131         
     
    117117                # We cannot figure out how to return a tuple here without gtk complaining 
    118118                lat, lon = self.convert_to_degrees((event.x, event.y)) 
    119                 self.emit("location_clicked", lat, lon) 
     119                self.emit("location_clicked", (lat, lon)) 
    120120         
    121121         
     
    164164        Test the `MapWidget`. 
    165165        ''' 
    166         def location_clicked_cb(widget, lat, lon): 
     166        def location_clicked_cb(widget, (lat, lon)): 
    167167                widget.draw_point((lat, lon), "green") 
    168168                print "location clicked %s %s" % (lat, lon) 
  • trunk/software/rb/shell.py

    r431 r445  
    2626import rbconfig 
    2727from rb.controller import Controller 
     28from rb.transcript import TranscriptLogger 
    2829 
    2930class Shell(cmd.Cmd, Controller): 
     
    3738                cmd.Cmd.__init__(self) 
    3839                Controller.__init__(self) 
    39                 self.set_mode('manual') 
     40                self.set_navigator('shell') 
    4041                try: 
    4142                        self.cmdloop() 
  • trunk/software/rb/wiimote.py

    r370 r445  
    1919 
    2020import time 
    21 from thread import start_new_thread 
     21import thread 
    2222 
    2323import cwiid 
    24 from cwiid import (LED1_ON, LED4_ON, FLAG_MESG_IFC, RPT_BTN, 
    25                                          RPT_STATUS, RPT_NUNCHUK, MESG_ERROR,  
    26                                          ERROR_DISCONNECT, ERROR_COMM, MESG_BTN) 
     24from cwiid import (LED1_ON, LED2_ON, LED3_ON, LED4_ON, BTN_A, 
     25                                         FLAG_MESG_IFC, RPT_BTN, RPT_STATUS, RPT_NUNCHUK, 
     26                                         MESG_ERROR, MESG_NUNCHUK, MESG_BTN, 
     27                                         ERROR_DISCONNECT, ERROR_COMM) 
    2728 
    2829import rbconfig 
    29 from rb.core.logging import log_debug, log_error, log_info 
     30from rb.core.logging import log_debug, log_error, log_info, log_die 
     31 
     32 
     33''' 
     34The zero point of the Wiimote nunchuk. 
     35''' 
     36STICK_CENTER = (124, 136) 
    3037 
    3138 
    3239class Wiimote(object): 
    3340        ''' 
    34         Controller for Wiimote control of the robot.  Some terrible contortions 
    35         are used here to get the cwiid stuff to run in the main thread --- without 
    36         that it  
     41        Controller for Wiimote control of the robot.  Because cwiid is 
     42        sensitive to what thread things are run in (in particular, the 
     43        ``cwiid.Wiimote`` class must be instantiated in the main 
     44        thread) some contortions are necessary to accomodate it. 
    3745        ''' 
    38         def __init__(self, addr=''): 
     46 
     47        def __init__(self, addr, controller): 
     48                ''' 
     49                Create a new Wiimote object.   
     50                ''' 
     51                self.running = False 
     52                self.addr = addr 
     53                self.controller = controller 
     54                self.wm = None 
     55                self.stick = STICK_CENTER # Latest stick data 
     56         
     57 
     58        def start(self): 
     59                ''' 
     60                Commence communications with the Wiimote if they have not already 
     61                been started.  Raise an IOError exception if the Wiimote cannot be 
     62                contacted. 
     63                ''' 
     64                if not self.running: 
     65                        self.connect() 
     66                        thread.start_new_thread(self._main, ()) 
     67 
     68        def connect(self): 
     69                ''' 
     70                Attempt to connect to the Wiimote.  Raise an IOError exception 
     71                on failure.  This method may block for a significant period (30 seconds 
     72                or so) and must be run in the main thread. 
     73                ''' 
     74                try: 
     75                        self.wm = cwiid.Wiimote(self.addr) 
     76                except RuntimeError, e: 
     77                        log_die('Wiimote: Unable to contact the wiimote') 
     78                        raise IOError('Wiimote not found') 
    3979                self.running = True 
    40                 self.killed = False # Set to True when the wiimote is powered off 
    41                 start_new_thread(self._main, (addr,)) 
    42                 self._main(addr) 
    4380         
    44         def _main(self, addr): 
     81                # Signal that the connection has been made 
     82                self.wm.rumble = True 
     83                time.sleep(.25) 
     84                self.wm.rumble = False 
     85                self.wm.rpt_mode = RPT_BTN | RPT_STATUS | RPT_NUNCHUK 
     86 
     87                self.wm.enable(FLAG_MESG_IFC) 
     88                self.wm.mesg_callback = self.handle_mesg 
     89 
     90        def stop(self): 
     91                if self.controller.navigator == 'wiimote': 
     92                        log_info('Wiimote: Switched navigator to manual') 
     93                        self.controller.set_navigator('manual') 
     94                self.wm.close() 
     95                self.wm = None 
     96                self.running = False 
     97 
     98        def _main(self): 
     99                while self.running: 
     100                        if self.controller.navigator == 'wiimote': 
     101                            self._control() 
     102                            time.sleep(.05) 
     103                        else: 
     104                            time.sleep(.1) 
     105 
     106        # FIXME: Integrate this somehow 
     107        def _control(self): 
    45108                ''' 
    46                 Continually try to connect to the Wiimote. 
     109                Set the motors based on the Wiimote's Nunchuk's analog stick. 
    47110                ''' 
    48                 while self.running: 
    49                         try: 
    50                                 self.wm = cwiid.Wiimote(addr) 
    51                                  
    52                                 # Signal that the connection has been made 
    53                                 self.wm.led = LED1_ON | LED4_ON 
    54                                 self.wm.rumble = True 
    55                                 time.sleep(.25) 
    56                                 self.wm.rumble = False 
    57                                 self.wm.enable(FLAG_MESG_IFC) 
    58                                 self.wm.rpt_mode = RPT_BTN | RPT_STATUS | RPT_NUNCHUK 
    59                                  
    60                                 self._communicate() 
    61                         except RuntimeError, e: # No wiimote found, or connection lost 
    62                                 time.sleep(.1) 
    63                                 print e 
    64                                 continue 
    65          
    66         def _communicate(self): 
     111                cx, cy = STICK_CENTER 
     112                x = float(self.stick[0] - cx) 
     113                y = float(self.stick[1] - cy) 
     114 
     115                lspeed = x / 127.0 if (abs(x) > 5) else 0 
     116                rspeed = y / 127.0 if (abs(y) > 5) else 0 
     117 
     118                self.controller.set_speed(lspeed, rspeed) 
     119 
     120        def handle_mesg(self, messages): 
    67121                ''' 
    68                 Primary wiimote communication loop. 
     122                Handle messages from the Wiimote.  Be careful here, as cwiid 
     123                swallows exceptions. 
    69124                ''' 
    70                 while True: 
    71                         for type, data in self.wm.get_mesg(): 
     125                try: 
     126                        for type, data in messages: 
    72127                                if type == MESG_ERROR: 
    73128                                        if data == ERROR_DISCONNECT: 
    74                                                 self.killed = True 
    75                                                 self.running = False 
     129                                                log_info("Wiimote: Disconnected") 
     130                                                self.stop() 
    76131                                        elif data == ERROR_COMM: 
    77132                                                log_info("Wiimote: ERROR_COMM encountered") 
    78133                                elif type == MESG_BTN: 
    79                                         print "Button(s) pressed: ", data 
     134                                        if data & BTN_A: 
     135                                                if self.controller.navigator != 'autonomous': 
     136                                                        self.controller.set_navigator('autonomous') 
     137                                                        log_info('Wiimote: Switched to autonomous navigator') 
    80138                                elif type == MESG_NUNCHUK: 
    81                                         print "Message:", (type, data) 
     139                                        self.stick = data['stick'] 
     140                except Exception, e: 
     141                        print e 
     142                        self.running = False 
     143 
    82144 
    83145if __name__ == '__main__': 
  • trunk/software/rbconfig.py

    r400 r445  
    1515 
    1616# Serial port for the motor controller 
     17fake_drive = True 
    1718left_motor_port  = '/dev/ttyUSB0' 
    1819right_motor_port = '/dev/ttyUSB1' 
     
    2324 
    2425 
    25 # Wiimote control 
     26# Wiimote controller to use 
     27# Set this to '' to try to connect to any Wiimote 
    2628wiimote_addr = '00:19:1D:2C:F2:37' 
    2729