Changeset 458
- Timestamp:
- 03/14/09 16:57:27 (3 years ago)
- Location:
- trunk/software
- Files:
-
- 1 added
- 8 modified
-
rb/auto.py (modified) (4 diffs)
-
rb/controller.py (modified) (5 diffs)
-
rb/drive.py (modified) (5 diffs)
-
rb/gui/analog.py (modified) (1 diff)
-
rb/gui/gui.py (modified) (3 diffs)
-
rb/gui/speedgraph.py (modified) (2 diffs)
-
rb/kalman.py (added)
-
rb/shell.py (modified) (1 diff)
-
rbconfig.py (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
trunk/software/rb/auto.py
r445 r458 18 18 ''' 19 19 20 import sys21 20 import time 22 import itertools23 21 from math import pi 24 25 22 26 23 from rb.core.logging import log_debug, log_info, log_warn, log_error, log_die 27 24 from rb.utils import points_to_vec, rad_delta 28 from rb.gps import GPS 29 from rb.microstrain import MicroStrain 30 from rb.drive import Drive, FakeDrive 31 import rbconfig 25 32 26 33 27 … … 40 34 41 35 42 43 36 class PointNavigator(object): 44 37 ''' 45 38 Implements the navigation algorithm of heading directly toward 46 a point.39 a GPS coordinate. 47 40 ''' 48 41 49 def __init__(self): 50 ''' 51 Create a new `PointNavigator`. 52 ''' 53 self.running = True 54 # Whether the robot is under manual Wiimote control or 55 # is autonomous. 56 self.autonomous = False 57 self.led = LED4_ON 42 def __init__(self, controller): 43 self.controller = controller 58 44 59 # Hardware60 self.gps = None61 self.microstrain = None62 self.drive = None63 self.wiimote = None64 65 # Data structures66 self.accel = None # Microstrain data67 self.coords = None # GPS data68 self.stick = STICK_CENTER # Wiimote's stick69 45 70 def run(self): 71 self.init_sensors() 72 self.init_output() 73 self.init_wiimote() 74 self.set_leds() 75 # Get a function that returns False every 5 calls 76 skip_led = itertools.cycle(range(5)).next 77 try: 78 while self.running: 79 if self.autonomous: 80 if self.get_inputs(): 81 self.set_outputs() 82 else: 83 self.wiimote_control() 84 time.sleep(.1) 85 if not skip_led(): 86 self.set_leds() 87 finally: 88 log_info("auto: Halting") 89 self.stop_output() 90 self.stop_sensors() 91 self.stop_wiimote() 92 93 def stop(self): 94 self.running = False 95 96 def init_sensors(self): 97 self.gps = GPS(rbconfig.gps_port) 98 self.microstrain = MicroStrain(rbconfig.microstrain_port) 99 100 def stop_sensors(self): 101 self.gps.running = False 102 self.microstrain.running = False 103 104 def init_output(self): 105 self.drive = Drive(rbconfig.left_motor_port, rbconfig.right_motor_port) 106 107 def stop_output(self): 108 self.drive.set_speeds(0, 0) 109 time.sleep(.5) 110 self.drive.running = False 111 112 113 114 def get_inputs(self): 115 ''' 116 Get input from the sensors, placing it in the `current_data` 117 attribute. Return True if anything has changed. 118 ''' 119 old = (self.accel, self.coords) 120 self.accel = self.microstrain.latest_state 121 self.coords = self.gps.latest_coords 122 if self.accel is not None and (time.time() - self.accel.timestamp) > 1: 123 self.accel = None 124 if self.coords is not None and (time.time() - self.coords.timestamp) > 5: 125 self.coords = None 126 return old != (self.accel, self.coords) 127 128 def set_outputs(self): 46 def _main(self): 129 47 ''' 130 48 Update the output based on `current_data`. … … 132 50 SPEED = .75 133 51 if self.accel is not None: 134 # The MicroStrain things that North is zero radians and that135 # radians increase clockwise. Change it so that 0 rad is east136 # and radians increase counter-clockwise.137 facing_dir = (((2 * pi) - self.accel.orient[2]) + (pi / 2)) % (2 * pi)138 52 log_info('Facing: %6.02f' % facing_dir) 139 53 else: … … 176 90 time.sleep(1) 177 91 self.wiimote.rumble = False 178 179 180 181 if __name__ == '__main__':182 pn = PointNavigator()183 pn.run() -
trunk/software/rb/controller.py
r445 r458 1 import gobject 2 1 3 import rbconfig 2 4 import rb.drive … … 4 6 import rb.microstrain 5 7 import rb.wiimote 8 import rb.kalman 6 9 7 10 class Controller(object): 11 ''' 12 A controller forms the core logic of the robot. It is responsible for 13 initializing hardware and routing sensor data everywhere it must go. 14 ''' 15 8 16 def __init__(self): 9 17 self.navigator = None … … 12 20 self.microstrain = None 13 21 self.wiimote = None 22 self.kalman = rb.kalman.KalmanFilter(self) 14 23 15 24 def set_navigator(self, nav): … … 23 32 def init_drive(self): 24 33 if rbconfig.fake_drive: 25 self.drive = rb.drive.FakeDrive(rbconfig.left_motor_port, 34 self.drive = rb.drive.FakeDrive(self, 35 rbconfig.left_motor_port, 26 36 rbconfig.right_motor_port) 27 37 else: 28 self.drive = rb.drive.Drive(rbconfig.left_motor_port, 38 self.drive = rb.drive.Drive(self, 39 rbconfig.left_motor_port, 29 40 rbconfig.right_motor_port) 30 41 … … 37 48 def init_wiimote(self): 38 49 self.wiimote = rb.wiimote.Wiimote(rbconfig.wiimote_addr, self) 50 51 52 ## 53 # Data routing 54 55 def send(self, type, data): 56 ''' 57 Send the data `data` for processing. `type` is a string 58 indicating the type of data, such as "gps" or "microstrain". 59 ''' 60 # Use gobject.idle_add to call `process()` in the main 61 # thread. 62 gobject.idle_add(self.process, type, data) 63 64 def process(self, type, data): 65 ''' 66 Process the data `data` of the type `type`. By default 67 this just updates the Kalman filter. 68 ''' 69 if type == 'gps_fix': 70 self.kalman.update_gps(data) 71 elif type == 'microstrain': 72 self.kalman.update_microstrain(data) 73 elif type == 'drive_targets': 74 pass 75 elif type == 'drive_speeds': 76 self.kalman.update_drive_speed(data) -
trunk/software/rb/drive.py
r454 r458 24 24 25 25 import struct 26 import time 27 import random 26 28 from serial import Serial 27 29 from thread import start_new_thread 28 30 from threading import Lock 29 from time import sleep31 from math import sin, cos 30 32 31 33 from rb.core.logging import log_error, log_debug … … 142 144 self.current = 0 # Latest reported speed of the motors 143 145 self._port = Serial(port, 19200, timeout=.5) 144 sleep(1)146 time.sleep(1) 145 147 self._port_lock = Lock() 146 148 start_new_thread(self._main, ()) … … 163 165 else: 164 166 print "Motor._main: timeout getting speed" 165 sleep(.05)167 time.sleep(.05) 166 168 print "Motor._main: exiting" 167 169 self._send("setspeed", 0) … … 216 218 ''' 217 219 218 def __init__(self, *args, **kwargs): 219 log_debug("MockDrive: __init__(*%s, **%s)" % (args, kwargs)) 220 def __init__(self, controller, *args, **kwargs): 221 log_debug("MockDrive: __init__(%s, *%s, **%s)" % (controller, args, kwargs)) 222 self.controller = controller 223 self.running = True 220 224 self.left = FakeMotor() 221 225 self.right = FakeMotor() 226 start_new_thread(self._main, ()) 227 228 def _main(self): 229 while self.running: 230 self.controller.send('drive_speeds', self.getspeed()) 231 time.sleep(.05) 222 232 223 233 def setspeed(self, left, right): … … 226 236 self.left.target = clip(left, -1.0, 1.0) 227 237 self.right.target = clip(right, -1.0, 1.0) 238 self.controller.send('drive_targets', (self.left.target, self.right.target)) 239 240 def gettarget(self): 241 return (self.left.target, self.right.target) 228 242 229 243 def getspeed(self): 230 return (self.left.target, self.right.target) 244 v1 = sin(time.time()) * .05 - random.random() * .01 245 v2 = cos(time.time()) * .05 - random.random() * .01 246 return (self.left.target + v1, self.right.target + v2) 231 247 232 248 -
trunk/software/rb/gui/analog.py
r454 r458 14 14 self.add_events(gtk.gdk.BUTTON_PRESS_MASK) 15 15 self.add_events(gtk.gdk.POINTER_MOTION_MASK) 16 self.connect("expose-event", self.expose_cb)16 self.connect("expose-event", self.expose_cb) 17 17 self.connect("motion-notify-event", self.motion_cb) 18 18 -
trunk/software/rb/gui/gui.py
r454 r458 67 67 self.builder.get_object("compass_body").add(self.compass) 68 68 self.builder.get_object("speed_graph").add(self.speed_graph) 69 69 70 70 self.window.show_all() 71 71 self.set_navigator('analog') 72 72 73 73 gtk.main() 74 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 74 75 def process(self, type, data): 76 Controller.process(self, type, data) 77 if type == 'drive_targets': 78 self.analog.queue_draw() 79 elif type == 'drive_speeds': 80 self.analog.queue_draw() 81 95 82 def set_navigator(self, nav): 96 83 ''' … … 121 108 self.update_nav_toggles() 122 109 110 def wiimote_connect(self): 111 sb = self.builder.get_object('statusbar') 112 context_id = sb.get_context_id('wiimote_connect') 113 # FIXME: Make the first message show up before we do the blocking start() call 114 msg = 'Connecting to the Wiimote at %s' % rbconfig.wiimote_addr 115 print msg 116 sb.push(context_id, msg) 117 try: 118 self.wiimote.start() 119 except IOError: 120 success = False 121 msg = 'Wiimote connection failed' 122 else: 123 success = True 124 msg = 'Connected to the Wiimote at %s' % rbconfig.wiimote_addr 125 sb.pop(context_id) 126 message_id = sb.push(context_id, msg) 127 gobject.timeout_add(3000, lambda: sb.remove(context_id, message_id)) 128 return success 129 123 130 def key_press_cb(self, widget, event): 124 131 nb = self.builder.get_object("notebook") … … 131 138 # Switch tabs 132 139 elif event.keyval == gtk.keysyms.Tab: 133 nb.set_current_page( not tab) # FIXME: make this robust140 nb.set_current_page((tab + 1) % nb.get_n_pages()) 134 141 135 142 # Set motor speeds -
trunk/software/rb/gui/speedgraph.py
r454 r458 50 50 center_y = a.height / 2.0 51 51 52 context.rectangle(0, 0, a.width, a.height) 53 context.set_source_rgb(1, 1, 1) 54 context.fill() 55 52 56 if len(self.ldata) < DATA_WINDOW: 53 57 start_x = a.width * (1 - len(self.ldata) / float(DATA_WINDOW)) … … 55 59 start_x = 0 56 60 step_x = a.width / float(DATA_WINDOW) 57 self.draw_line(context, center_y, start_x, step_x, ( 0, 100,0), self.ldata[-DATA_WINDOW:])58 self.draw_line(context, center_y, start_x, step_x, ( 0, 200,0), self.ltargets[-DATA_WINDOW:])59 self.draw_line(context, center_y, start_x, step_x, ( 100, 0,0), self.rdata[-DATA_WINDOW:])60 self.draw_line(context, center_y, start_x, step_x, ( 200, 0,0), self.rtargets[-DATA_WINDOW:])61 self.draw_line(context, center_y, start_x, step_x, ( 0, .5, 0), self.ldata[-DATA_WINDOW:]) 62 self.draw_line(context, center_y, start_x, step_x, ( 0, 1, 0), self.ltargets[-DATA_WINDOW:]) 63 self.draw_line(context, center_y, start_x, step_x, (.5, 0, 0), self.rdata[-DATA_WINDOW:]) 64 self.draw_line(context, center_y, start_x, step_x, ( 1, 0, 0), self.rtargets[-DATA_WINDOW:]) 61 65 62 66 return False -
trunk/software/rb/shell.py
r454 r458 49 49 } 50 50 self.init_drive() 51 51 52 try: 52 53 sessfile = os.environ['RB_SHELL_AUTORUN'] -
trunk/software/rbconfig.py
r454 r458 15 15 16 16 # Serial port for the motor controller 17 fake_drive = False17 fake_drive = True 18 18 left_motor_port = '/dev/ttyUSB0' 19 19 right_motor_port = '/dev/ttyUSB1'

