source: trunk/brainstorms/Puzzlebox/Brainstorms/Interface.py @ 246

Last change on this file since 246 was 246, checked in by sc, 11 years ago

Interface.py:

  • COM port search tweaks for win32

setup.py:

  • removed erroneous matplotlib references
File size: 53.7 KB
Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3#
4# Puzzlebox - Brainstorms - Client Interface - Qt
5#
6# Copyright Puzzlebox Productions, LLC (2010)
7#
8# This code is released under the GNU Pulic License (GPL) version 2
9# For more information please refer to http://www.gnu.org/copyleft/gpl.html
10
11__changelog__ = """\
12Last Update: 2010.12.04
13
14"""
15
16__todo__ = """
17 - server may not correctly handle multiple clients connected
18      to an embedded Brainstorms server
19 - disable autorepeating on shortcut keys
20 - update configuration.ini file with settings entered into interface
21
22"""
23
24import os, sys
25import urllib
26
27if (sys.platform == 'win32'):
28        DEFAULT_IMAGE_PATH = 'images'
29        import _winreg as winreg
30        import itertools
31        import re
32        import serial
33else:
34        DEFAULT_IMAGE_PATH = '/usr/share/puzzlebox_brainstorms/images'
35        import bluetooth
36        os.chdir('/usr/share/puzzlebox_brainstorms')
37
38try:
39        import PySide as PyQt4
40        from PySide import QtCore, QtGui, QtNetwork
41except:
42        print "Using PyQt4 module"
43        from PyQt4 import QtCore, QtGui, QtNetwork
44else:
45        print "Using PySide module"
46
47#from PyQt4 import QtCore, QtGui, QtNetwork
48#from PySide import QtCore, QtGui, QtNetwork
49
50from Interface_Design import Ui_Form as Design
51
52import simplejson as json
53
54import Configuration as configuration
55import Client as brainstorms_client
56import Puzzlebox.Brainstorms.ThinkGear.Client as thinkgear_client
57import Helicopter_Control as helicopter_control
58import Wheelchair_Control as wheelchair_control
59#import puzzlebox_logger
60
61#####################################################################
62# Globals
63#####################################################################
64
65DEBUG = 1
66
67THINKGEAR_POWER_THRESHOLDS = configuration.THINKGEAR_POWER_THRESHOLDS
68
69BLUETOOTH_DEVICE = configuration.NXT_BLUETOOTH_DEVICE
70
71NXT_BLUETOOTH_DEVICE = configuration.NXT_BLUETOOTH_DEVICE
72
73DEFAULT_NXT_POWER_LEVEL = configuration.DEFAULT_NXT_POWER_LEVEL
74
75THINKGEAR_SERVER_HOST = configuration.THINKGEAR_SERVER_HOST
76THINKGEAR_SERVER_PORT = configuration.THINKGEAR_SERVER_PORT
77
78BRAINSTORMS_FEEDBACK_URL = 'http://brainstorms.puzzlebox.info/contact_cgi.php'
79
80DEVICE_PATH = '/dev'
81PATH_TO_HCITOOL = '/usr/bin/hcitool'
82
83#####################################################################
84# Classes
85#####################################################################
86
87class puzzlebox_brainstorms_client_interface(QtGui.QWidget, Design):
88       
89        def __init__(self, log, server=None, DEBUG=DEBUG, parent = None):
90               
91                self.log = log
92                self.DEBUG = DEBUG
93               
94                QtGui.QWidget.__init__(self, parent)
95                self.setupUi(self)
96               
97                self.configureSettings()
98                self.connectWidgets()
99               
100                self.name = "Brainstorms Interface"
101               
102                self.brainstormsServer = server
103                self.brainstormsClient = None
104               
105                self.helicopter = None
106                self.wheelchair = None
107               
108                self.drive_state = 'stop_motors'
109                self.current_speed = 0
110               
111                self.current_helicopter_state = 'neutral'
112       
113       
114        ##################################################################
115       
116        def configureSettings(self):
117               
118                # Brainstorms Interface
119               
120                image_path = "puzzlebox.ico"
121                if not os.path.exists(image_path):
122                        image_path = os.path.join(DEFAULT_IMAGE_PATH, image_path)
123               
124                if os.path.exists(image_path):
125                        icon = QtGui.QIcon()
126                        icon.addPixmap(QtGui.QPixmap(image_path), \
127                                            QtGui.QIcon.Normal, \
128                                            QtGui.QIcon.Off)
129                        self.setWindowIcon(icon)
130               
131                image_path = "puzzlebox_logo.png"
132                if not os.path.exists(image_path):
133                        image_path = os.path.join(DEFAULT_IMAGE_PATH, image_path)
134                if os.path.exists(image_path):
135                        self.labelPuzzlebox.setPixmap(QtGui.QPixmap(image_path))
136               
137                self.pushButtonTurnLeft.setEnabled(False)
138                self.pushButtonForward.setEnabled(False)
139                self.pushButtonTurnRight.setEnabled(False)
140                self.pushButtonTurnLeftReverse.setEnabled(False)
141                self.pushButtonReverse.setEnabled(False)
142                self.pushButtonTurnRightReverse.setEnabled(False)
143               
144                self.pushButtonConcentrationEnable.setDown(True)
145                self.pushButtonRelaxationEnable.setDown(True)
146                self.pushButtonSpeedEnable.setDown(True)
147               
148               
149                # Search for available Serial and Bluetooth devices
150                self.searchForDevices()
151               
152               
153                # LEGO Mindstorms
154                self.textLabelNXTStatus.setText("Status: Disconnected")
155               
156                # Display communication port for LEGO Mindstorms NXT device
157                #self.lineEditNXTPort.setText(NXT_BLUETOOTH_DEVICE)
158                self.comboBoxNXTPortSelect.setEnabled(True)
159               
160               
161                # RC Helicopter
162                self.textLabelHelicopterStatus.setText("Status: Disconnected")
163               
164               
165                # Wheelchair
166                self.textLabelWheelchairStatus.setText("Status: Disconnected")
167               
168               
169                # Control Panel
170               
171                # Display Host for ThinkGear Connect Socket Server
172                self.lineEditThinkGearHost.setText(THINKGEAR_SERVER_HOST)
173                #self.lineEditThinkGearHost.setEnabled(False)
174               
175                # Display Port for ThinkGear Connect Socket Server
176                self.lineEditThinkGearPort.setText('%i' % THINKGEAR_SERVER_PORT)
177                #self.lineEditThinkGearPort.setEnabled(False)
178               
179               
180                self.lineEditLeftMotorPort.setText( \
181                   configuration.NXT_MOTOR_PORT_LEFT.upper() )
182                self.lineEditRightMotorPort.setText(   \
183                   configuration.NXT_MOTOR_PORT_RIGHT.upper() )
184                self.checkBoxMotorSpinReversed.setChecked( \
185                   configuration.NXT_MOTORS_MOUNTED_BACKWARDS)
186       
187       
188        ##################################################################
189       
190        def getMinimumThreshold(self, threshold):
191               
192                '''Return the minimum detection level which results
193                in a non-zero power setting'''
194               
195                minimum = 100
196               
197                threshold_keys = threshold.keys()
198                threshold_keys.sort()
199                threshold_keys.reverse()
200               
201                for key in threshold_keys:
202                       
203                        if ((threshold[key] < minimum) and \
204                                 (threshold[key] > 0)):
205                                minimum = key
206               
207               
208                return(minimum)
209       
210       
211        ##################################################################
212       
213        def configureNetworkBrainstorms(self):
214               
215                bluetooth_device = str(self.comboBoxNXTPortSelect.currentText())
216               
217                self.brainstormsClient = \
218                   brainstorms_client.puzzlebox_brainstorms_network_client( \
219                           self.log, \
220                           bluetooth_device=bluetooth_device, \
221                           parent=self)
222               
223                self.brainstormsClient.sendCommand('connect', \
224                                                   bluetooth_device=bluetooth_device)
225       
226       
227        ##################################################################
228       
229        def connectToBrainstormsServer(self):
230               
231                # Prevent attempting to connect to a device which does not exist
232                device = str(self.comboBoxNXTPortSelect.currentText())
233                if device == 'N/A':
234                        self.pushButtonNXTConnect.setChecked(False)
235                        return
236                if (sys.platform != 'win32'):
237                        if ((not device.startswith(DEVICE_PATH)) or \
238                            (not os.path.exists(device))):
239                                self.searchForDevices()
240                                self.pushButtonNXTConnect.setChecked(False)
241                                return
242               
243               
244                if self.DEBUG:
245                        print "<---- [%s] Connecting to Brainstorms Server" % self.name
246               
247                self.configureNetworkBrainstorms()
248               
249                #if (self.brainstormsClient.socket.state() != QtNetwork.QAbstractSocket.ConnectedState):
250                        #QtGui.QMessageBox.information(self, \
251                                                                #self.brainstormsClient.socket.name, \
252                                           #"Failed to connect to Brainstorms socket server")
253               
254                #else:
255                self.disconnect(self.pushButtonNXTConnect, \
256                                                        QtCore.SIGNAL("clicked()"), \
257                                                        self.connectToBrainstormsServer)
258               
259                self.connect(self.pushButtonNXTConnect, \
260                                                        QtCore.SIGNAL("clicked()"), \
261                                                        self.disconnectFromBrainstormsServer)
262               
263                self.textLabelNXTStatus.setText("Status: Connected")
264                self.pushButtonNXTConnect.setText('Disconnect')
265               
266                self.comboBoxNXTPortSelect.setEnabled(False)
267                self.pushButtonNXTSearch.setEnabled(False)
268               
269                self.pushButtonTurnLeft.setEnabled(True)
270                self.pushButtonForward.setEnabled(True)
271                self.pushButtonTurnRight.setEnabled(True)
272                self.pushButtonTurnLeftReverse.setEnabled(True)
273                self.pushButtonReverse.setEnabled(True)
274                self.pushButtonTurnRightReverse.setEnabled(True)
275               
276                self.pushButtonNXTMessageOne.setEnabled(True)
277                self.pushButtonNXTMessageTwo.setEnabled(True)
278                self.pushButtonNXTMessageThree.setEnabled(True)
279                self.pushButtonNXTMessageFour.setEnabled(True)
280                self.pushButtonNXTMessageFive.setEnabled(True)
281                self.pushButtonNXTMessageSix.setEnabled(True)
282               
283                self.pushButtonConcentrationEnable.setEnabled(True)
284                self.pushButtonRelaxationEnable.setEnabled(True)
285                self.pushButtonSpeedEnable.setEnabled(True)
286               
287                self.pushButtonMessageOne.setEnabled(True)
288                self.pushButtonMessageTwo.setEnabled(True)
289                self.pushButtonMessageThree.setEnabled(True)
290                self.pushButtonMessageFour.setEnabled(True)
291                self.pushButtonMessageFive.setEnabled(True)
292                self.pushButtonMessageSix.setEnabled(True)
293       
294       
295        ##################################################################
296       
297        def disconnectFromBrainstormsServer(self):
298               
299                if self.DEBUG:
300                        print "- - [%s] Disconnecting from Brainstorms Server" % self.name
301               
302                self.stopMotors()
303               
304                # Ensure the stopMotors command has been received by the server
305                # so the NXT robot will stop before the client disconnects
306                self.brainstormsClient.socket.flush()
307               
308                self.brainstormsClient.socket.disconnectFromHost()
309               
310                self.disconnect(self.pushButtonNXTConnect, \
311                                  QtCore.SIGNAL("clicked()"), \
312                                  self.disconnectFromBrainstormsServer)
313               
314                self.connect(self.pushButtonNXTConnect, \
315                                  QtCore.SIGNAL("clicked()"), \
316                                  self.connectToBrainstormsServer)
317               
318                self.textLabelNXTStatus.setText("Status: Disconnected")
319                self.pushButtonNXTConnect.setText('Connect')
320               
321                self.comboBoxNXTPortSelect.setEnabled(True)
322                self.pushButtonNXTSearch.setEnabled(True)
323               
324                self.pushButtonTurnLeft.setEnabled(False)
325                self.pushButtonForward.setEnabled(False)
326                self.pushButtonTurnRight.setEnabled(False)
327                self.pushButtonTurnLeftReverse.setEnabled(False)
328                self.pushButtonReverse.setEnabled(False)
329                self.pushButtonTurnRightReverse.setEnabled(False)
330               
331                self.pushButtonNXTMessageOne.setEnabled(False)
332                self.pushButtonNXTMessageTwo.setEnabled(False)
333                self.pushButtonNXTMessageThree.setEnabled(False)
334                self.pushButtonNXTMessageFour.setEnabled(False)
335                self.pushButtonNXTMessageFive.setEnabled(False)
336                self.pushButtonNXTMessageSix.setEnabled(False)
337               
338                self.pushButtonConcentrationEnable.setEnabled(False)
339                self.pushButtonRelaxationEnable.setEnabled(False)
340                self.pushButtonSpeedEnable.setEnabled(False)
341               
342                self.pushButtonMessageOne.setEnabled(False)
343                self.pushButtonMessageTwo.setEnabled(False)
344                self.pushButtonMessageThree.setEnabled(False)
345                self.pushButtonMessageFour.setEnabled(False)
346                self.pushButtonMessageFive.setEnabled(False)
347                self.pushButtonMessageSix.setEnabled(False)
348               
349                self.brainstormsClient = None
350               
351                self.searchForDevices()
352       
353       
354        ##################################################################
355       
356        def connectToThinkGearHost(self):
357               
358                if self.DEBUG:
359                        print "Connecting to ThinkGear Host"
360               
361                server_host = str(self.lineEditThinkGearHost.text())
362                server_port = int(self.lineEditThinkGearPort.text())
363               
364                self.thinkgearClient = \
365                   thinkgear_client.puzzlebox_brainstorms_network_client_thinkgear( \
366                           self.log, \
367                           server_host=server_host, \
368                           server_port=server_port, \
369                           DEBUG=0, \
370                           parent=self)
371               
372                if (self.thinkgearClient.socket.state() != QtNetwork.QAbstractSocket.ConnectedState):
373                        QtGui.QMessageBox.information(self, \
374                                                                self.thinkgearClient.socket.name, \
375                                           "Failed to connect to ThinkGear socket server")
376               
377                else:
378                        self.disconnect(self.pushButtonThinkGearConnect, \
379                                                         QtCore.SIGNAL("clicked()"), \
380                                                         self.connectToThinkGearHost)
381                       
382                        self.connect(self.pushButtonThinkGearConnect, \
383                                                         QtCore.SIGNAL("clicked()"), \
384                                                         self.disconnectFromThinkGearHost)
385                       
386                        self.pushButtonThinkGearConnect.setText('Disconnect')
387                       
388                        self.comboBoxEEGHeadsetModel.setEnabled(False)
389                        self.comboBoxEEGSource.setEnabled(False)
390                        self.lineEditThinkGearHost.setEnabled(False)
391                        self.lineEditThinkGearPort.setEnabled(False)
392       
393       
394        ##################################################################
395       
396        def disconnectFromThinkGearHost(self):
397               
398                if self.DEBUG:
399                        print "Disconnecting from ThinkGear Host"
400               
401                self.thinkgearClient.disconnectFromHost()
402               
403                self.disconnect(self.pushButtonThinkGearConnect, \
404                                  QtCore.SIGNAL("clicked()"), \
405                                  self.disconnectFromThinkGearHost)
406               
407                self.connect(self.pushButtonThinkGearConnect, \
408                                  QtCore.SIGNAL("clicked()"), \
409                                  self.connectToThinkGearHost)
410               
411                self.pushButtonForward.emit(QtCore.SIGNAL("released()"))
412               
413                self.pushButtonThinkGearConnect.setText('Connect')
414               
415                self.comboBoxEEGHeadsetModel.setEnabled(True)
416                self.comboBoxEEGSource.setEnabled(True)
417                self.lineEditThinkGearHost.setEnabled(True)
418                self.lineEditThinkGearPort.setEnabled(True)
419               
420                self.progressBarConcentration.setValue(0)
421                self.progressBarRelaxation.setValue(0)
422                self.progressBarSpeed.setValue(0)
423       
424                self.progressBarHelicopterConcentration.setValue(0)
425                self.progressBarHelicopterRelaxation.setValue(0)
426                self.progressBarHelicopterSpeed.setValue(0)
427       
428                self.progressBarWheelchairConcentration.setValue(0)
429                self.progressBarWheelchairRelaxation.setValue(0)
430                self.progressBarWheelchairSpeed.setValue(0)
431       
432       
433        ##################################################################
434       
435        def connectToRCHelicopter(self):
436
437                # Prevent attempting to connect to a device which does not exist
438                device = str(self.comboBoxNXTPortSelect.currentText())
439                if device == 'N/A':
440                        self.pushButtonHelicopterConnect.setChecked(False)
441                        return
442                if (sys.platform != 'win32'):
443                        if ((not device.startswith(DEVICE_PATH)) or \
444                            (not os.path.exists(device))):
445                                self.searchForDevices()
446                                self.pushButtonHelicopterConnect.setChecked(False)
447                                return
448
449                self.helicopter = \
450                   helicopter_control.puzzlebox_brainstorms_helicopter_control( \
451                      device_address=device,
452                      command='neutral', \
453                      DEBUG=self.DEBUG)
454               
455                self.helicopter.start()
456               
457                self.disconnect(self.pushButtonHelicopterConnect, \
458                                  QtCore.SIGNAL("clicked()"), \
459                                  self.connectToRCHelicopter)
460               
461                self.connect(self.pushButtonHelicopterConnect, \
462                                  QtCore.SIGNAL("clicked()"), \
463                                  self.disconnectFromRCHelicopter)
464               
465                self.pushButtonHelicopterConnect.setText('Disconnect')
466               
467                self.comboBoxHelicopterTransmitter.setEnabled(False)
468                self.comboBoxHelicopterPortSelect.setEnabled(False)
469                self.pushButtonHelicopterSearch.setEnabled(False)
470               
471                self.pushButtonHelicopterHover.setEnabled(True)
472                self.pushButtonHelicopterFlyForward.setEnabled(True)
473                self.pushButtonHelicopterLand.setEnabled(True)
474                self.pushButtonHelicopterThrottle.setEnabled(True)
475                self.verticalSliderHelicopterThrottle.setEnabled(True)
476                self.pushButtonHelicopterElevatorForward.setEnabled(True)
477                self.verticalSliderHelicopterElevatorForward.setEnabled(True)
478                self.pushButtonHelicopterElevatorReverse.setEnabled(True)
479                self.verticalSliderHelicopterElevatorReverse.setEnabled(True)
480                self.pushButtonHelicopterRudderLeft.setEnabled(True)
481                self.horizontalSliderHelicopterRudderLeft.setEnabled(True)
482                self.pushButtonHelicopterRudderRight.setEnabled(True)
483                self.horizontalSliderHelicopterRudderRight.setEnabled(True)
484                self.pushButtonHelicopterAileronLeft.setEnabled(True)
485                self.horizontalSliderHelicopterAileronLeft.setEnabled(True)
486                self.pushButtonHelicopterAileronRight.setEnabled(True)
487                self.horizontalSliderHelicopterAileronRight.setEnabled(True)
488               
489                self.pushButtonHelicopterConcentrationEnable.setEnabled(True)
490                self.pushButtonHelicopterRelaxationEnable.setEnabled(True)
491                self.pushButtonHelicopterSpeedEnable.setEnabled(True)
492       
493       
494        ##################################################################
495       
496        def disconnectFromRCHelicopter(self):
497               
498                self.helicopter.neutral()
499                self.current_helicopter_state = 'neutral'
500               
501                self.helicopter.stop()
502               
503                self.disconnect(self.pushButtonHelicopterConnect, \
504                                  QtCore.SIGNAL("clicked()"), \
505                                  self.disconnectFromRCHelicopter)
506               
507                self.connect(self.pushButtonHelicopterConnect, \
508                                  QtCore.SIGNAL("clicked()"), \
509                                  self.connectToRCHelicopter)
510               
511                self.pushButtonHelicopterConnect.setText('Connect')
512               
513                self.comboBoxHelicopterTransmitter.setEnabled(True)
514                self.comboBoxHelicopterPortSelect.setEnabled(True)
515                self.pushButtonHelicopterSearch.setEnabled(True)
516               
517                self.pushButtonHelicopterHover.setEnabled(False)
518                self.pushButtonHelicopterFlyForward.setEnabled(False)
519                self.pushButtonHelicopterLand.setEnabled(False)
520                self.pushButtonHelicopterThrottle.setEnabled(False)
521                self.verticalSliderHelicopterThrottle.setEnabled(False)
522                self.pushButtonHelicopterElevatorForward.setEnabled(False)
523                self.verticalSliderHelicopterElevatorForward.setEnabled(False)
524                self.pushButtonHelicopterElevatorReverse.setEnabled(False)
525                self.verticalSliderHelicopterElevatorReverse.setEnabled(False)
526                self.pushButtonHelicopterRudderLeft.setEnabled(False)
527                self.horizontalSliderHelicopterRudderLeft.setEnabled(False)
528                self.pushButtonHelicopterRudderRight.setEnabled(False)
529                self.horizontalSliderHelicopterRudderRight.setEnabled(False)
530                self.pushButtonHelicopterAileronLeft.setEnabled(False)
531                self.horizontalSliderHelicopterAileronLeft.setEnabled(False)
532                self.pushButtonHelicopterAileronRight.setEnabled(False)
533                self.horizontalSliderHelicopterAileronRight.setEnabled(False)
534               
535                self.pushButtonHelicopterConcentrationEnable.setEnabled(False)
536                self.pushButtonHelicopterRelaxationEnable.setEnabled(False)
537                self.pushButtonHelicopterSpeedEnable.setEnabled(False)
538       
539       
540        ##################################################################
541       
542        def connectToWheelchair(self):
543               
544                # Prevent attempting to connect to a device which does not exist
545                device = str(self.comboBoxNXTPortSelect.currentText())
546                if device == 'N/A':
547                        self.pushButtonWheelchairConnect.setChecked(False)     
548                        return
549                if (sys.platform != 'win32'):
550                        if ((not device.startswith(DEVICE_PATH)) or \
551                            (not os.path.exists(device))):
552                                self.searchForDevices()
553                                self.pushButtonWheelchairConnect.setChecked(False)
554                                return
555               
556                self.wheelchair = \
557                   wheelchair_control.puzzlebox_brainstorms_wheelchair_control( \
558                      device_address=device,
559                      command=None, \
560                      DEBUG=self.DEBUG)
561               
562                #self.wheelchair.start()
563               
564                self.disconnect(self.pushButtonWheelchairConnect, \
565                                  QtCore.SIGNAL("clicked()"), \
566                                  self.connectToWheelchair)
567               
568                self.connect(self.pushButtonWheelchairConnect, \
569                                  QtCore.SIGNAL("clicked()"), \
570                                  self.disconnectFromWheelchair)
571               
572                self.pushButtonWheelchairConnect.setText('Disconnect')
573               
574                self.comboBoxWheelchairTransmitter.setEnabled(False)
575                self.comboBoxWheelchairPortSelect.setEnabled(False)
576                self.pushButtonWheelchairSearch.setEnabled(False)
577               
578                self.pushButtonWheelchairForward.setEnabled(True)
579                self.pushButtonWheelchairReverse.setEnabled(True)
580                self.pushButtonWheelchairLeft.setEnabled(True)
581                self.pushButtonWheelchairRight.setEnabled(True)
582                self.pushButtonWheelchairStop.setEnabled(True)
583                self.dialWheelchairSpeed.setEnabled(True)
584               
585                self.pushButtonWheelchairConcentrationEnable.setEnabled(True)
586                self.pushButtonWheelchairRelaxationEnable.setEnabled(True)
587                self.pushButtonWheelchairSpeedEnable.setEnabled(True)
588               
589                # Safety Measure: Explicitely require wheelchair speed control
590                # to be enabled each time it wheelchair is connected
591                self.pushButtonWheelchairSpeedEnable.setChecked(False)
592                self.pushButtonWheelchairSpeedEnable.setText('Disabled')
593                self.progressBarWheelchairSpeed.setValue(0)
594       
595       
596        ##################################################################
597       
598        def disconnectFromWheelchair(self):
599               
600                self.stopWheelchair()
601               
602                #self.wheelchair.stop()
603               
604                self.disconnect(self.pushButtonWheelchairConnect, \
605                                  QtCore.SIGNAL("clicked()"), \
606                                  self.disconnectFromWheelchair)
607               
608                self.connect(self.pushButtonWheelchairConnect, \
609                                  QtCore.SIGNAL("clicked()"), \
610                                  self.connectToWheelchair)
611               
612                self.pushButtonWheelchairConnect.setText('Connect')
613               
614                self.comboBoxWheelchairTransmitter.setEnabled(True)
615                self.comboBoxWheelchairPortSelect.setEnabled(True)
616                self.pushButtonWheelchairSearch.setEnabled(True)
617               
618                self.pushButtonWheelchairForward.setEnabled(False)
619                self.pushButtonWheelchairReverse.setEnabled(False)
620                self.pushButtonWheelchairLeft.setEnabled(False)
621                self.pushButtonWheelchairRight.setEnabled(False)
622                self.pushButtonWheelchairStop.setEnabled(False)
623                self.dialWheelchairSpeed.setEnabled(False)
624               
625                self.pushButtonWheelchairConcentrationEnable.setEnabled(False)
626                self.pushButtonWheelchairRelaxationEnable.setEnabled(False)
627                self.pushButtonWheelchairSpeedEnable.setEnabled(False)
628               
629                # Safety Measure: Explicitely require wheelchair speed control
630                # to be enabled each time it wheelchair is connected
631                self.pushButtonWheelchairSpeedEnable.setChecked(False)
632                self.pushButtonWheelchairSpeedEnable.setText('Disabled')
633                self.progressBarWheelchairSpeed.setValue(0)
634       
635       
636        ##################################################################
637       
638        def updateConcentrationButton(self):
639               
640                if self.pushButtonConcentrationEnable.isChecked():
641                       
642                        self.pushButtonConcentrationEnable.setText('Enabled')
643               
644                else:
645                       
646                        self.pushButtonConcentrationEnable.setText('Disabled')
647                        self.progressBarConcentration.setValue(0)
648               
649               
650                self.updateSpeed()
651       
652       
653        ##################################################################
654       
655        def updateRelaxationButton(self):
656               
657                if self.pushButtonRelaxationEnable.isChecked():
658               
659                        self.pushButtonRelaxationEnable.setText('Enabled')
660               
661                else:
662                       
663                        self.pushButtonRelaxationEnable.setText('Disabled')
664                        self.progressBarRelaxation.setValue(0)
665               
666               
667                self.updateNXTSpeed()
668       
669       
670        ##################################################################
671       
672        def updateSpeedButton(self):
673               
674                if self.pushButtonSpeedEnable.isChecked():
675               
676                        self.pushButtonSpeedEnable.setText('Enabled')
677                        self.updateSpeed()
678               
679                else:
680                       
681                        self.pushButtonSpeedEnable.setText('Disabled')
682                        self.progressBarSpeed.setValue(0)
683                        self.stopMotors()
684       
685       
686        ##################################################################
687       
688        def updateHelicopterConcentrationButton(self):
689               
690                if self.pushButtonHelicopterConcentrationEnable.isChecked():
691                       
692                        self.pushButtonHelicopterConcentrationEnable.setText('Enabled')
693               
694                else:
695                       
696                        self.pushButtonHelicopterConcentrationEnable.setText('Disabled')
697                        self.progressBarHelicopterConcentration.setValue(0)
698               
699               
700                self.updateHelicopterSpeed()
701       
702       
703        ##################################################################
704       
705        def updateHelicopterRelaxationButton(self):
706               
707                if self.pushButtonHelicopterRelaxationEnable.isChecked():
708               
709                        self.pushButtonHelicopterRelaxationEnable.setText('Enabled')
710               
711                else:
712                       
713                        self.pushButtonHelicopterRelaxationEnable.setText('Disabled')
714                        self.progressBarHelicopterRelaxation.setValue(0)
715               
716               
717                self.updateHelicopterSpeed()
718       
719       
720        ##################################################################
721       
722        def updateHelicopterSpeedButton(self):
723               
724                if self.pushButtonHelicopterSpeedEnable.isChecked():
725               
726                        self.pushButtonHelicopterSpeedEnable.setText('Enabled')
727                        self.updateHelicopterSpeed()
728               
729                else:
730                       
731                        self.pushButtonHelicopterSpeedEnable.setText('Disabled')
732                        self.progressBarHelicopterSpeed.setValue(0)
733                        self.landHelicopter()
734       
735       
736        ##################################################################
737       
738        def updateWheelchairConcentrationButton(self):
739               
740                if self.pushButtonWheelchairConcentrationEnable.isChecked():
741                       
742                        self.pushButtonWheelchairConcentrationEnable.setText('Enabled')
743               
744                else:
745                       
746                        self.pushButtonWheelchairConcentrationEnable.setText('Disabled')
747                        self.progressBarWheelchairConcentration.setValue(0)
748               
749               
750                self.updateWheelchairSpeed()
751       
752       
753        ##################################################################
754       
755        def updateWheelchairRelaxationButton(self):
756               
757                if self.pushButtonWheelchairRelaxationEnable.isChecked():
758               
759                        self.pushButtonWheelchairRelaxationEnable.setText('Enabled')
760               
761                else:
762                       
763                        self.pushButtonWheelchairRelaxationEnable.setText('Disabled')
764                        self.progressBarWheelchairRelaxation.setValue(0)
765               
766               
767                self.updateWheelchairSpeed()
768       
769       
770        ##################################################################
771       
772        def updateWheelchairSpeedButton(self):
773               
774                if self.pushButtonWheelchairSpeedEnable.isChecked():
775               
776                        self.pushButtonWheelchairSpeedEnable.setText('Enabled')
777                        self.updateWheelchairSpeed()
778               
779                else:
780                       
781                        self.pushButtonWheelchairSpeedEnable.setText('Disabled')
782                        self.progressBarWheelchairSpeed.setValue(0)
783                        self.stopWheelchair()
784       
785       
786        ##################################################################
787       
788        def connectWidgets(self):
789               
790                # LEGO Mindstorms Buttons
791                self.connect(self.pushButtonTurnLeft, QtCore.SIGNAL("pressed()"), \
792                             self.turnLeft)
793                self.connect(self.pushButtonTurnLeft, QtCore.SIGNAL("released()"), \
794                             self.stopMotors)
795               
796                self.connect(self.pushButtonForward, QtCore.SIGNAL("pressed()"), \
797                             self.driveForward)
798                self.connect(self.pushButtonForward, QtCore.SIGNAL("released()"), \
799                             self.stopMotors)
800               
801                self.connect(self.pushButtonTurnRight, QtCore.SIGNAL("pressed()"), \
802                             self.turnRight)
803                self.connect(self.pushButtonTurnRight, QtCore.SIGNAL("released()"), \
804                             self.stopMotors)
805               
806                self.connect(self.pushButtonTurnLeftReverse, QtCore.SIGNAL("pressed()"), \
807                             self.turnLeftInReverse)
808                self.connect(self.pushButtonTurnLeftReverse, QtCore.SIGNAL("released()"), \
809                             self.stopMotors)
810               
811                self.connect(self.pushButtonReverse, QtCore.SIGNAL("pressed()"), \
812                             self.driveReverse)
813                self.connect(self.pushButtonReverse, QtCore.SIGNAL("released()"), \
814                             self.stopMotors)
815               
816                self.connect(self.pushButtonTurnRightReverse, QtCore.SIGNAL("pressed()"), \
817                             self.turnRightInReverse)
818                self.connect(self.pushButtonTurnRightReverse, QtCore.SIGNAL("released()"), \
819                             self.stopMotors)
820               
821               
822                self.connect(self.pushButtonNXTSearch, \
823                                  QtCore.SIGNAL("clicked()"), \
824                                  self.searchForDevices)
825               
826                self.connect(self.pushButtonNXTConnect, \
827                                  QtCore.SIGNAL("clicked()"), \
828                                  self.connectToBrainstormsServer)
829               
830               
831                self.connect(self.pushButtonConcentrationEnable, \
832                                  QtCore.SIGNAL("clicked()"), \
833                                  self.updateConcentrationButton)
834               
835                self.connect(self.pushButtonRelaxationEnable, \
836                                  QtCore.SIGNAL("clicked()"), \
837                                  self.updateRelaxationButton)
838               
839                self.connect(self.pushButtonSpeedEnable, \
840                                  QtCore.SIGNAL("clicked()"), \
841                                  self.updateSpeedButton)
842               
843               
844                self.connect(self.pushButtonNXTMessageOne, QtCore.SIGNAL("pressed()"), \
845                             self.sendMessageOne)
846               
847                self.connect(self.pushButtonNXTMessageTwo, QtCore.SIGNAL("pressed()"), \
848                             self.sendMessageTwo)
849               
850                self.connect(self.pushButtonNXTMessageThree, QtCore.SIGNAL("pressed()"), \
851                             self.sendMessageThree)
852               
853                self.connect(self.pushButtonNXTMessageFour, QtCore.SIGNAL("pressed()"), \
854                             self.sendMessageFour)
855               
856                self.connect(self.pushButtonNXTMessageFive, QtCore.SIGNAL("pressed()"), \
857                             self.sendMessageFive)
858               
859                self.connect(self.pushButtonNXTMessageSix, QtCore.SIGNAL("pressed()"), \
860                             self.sendMessageSix)
861               
862               
863               
864                # RC Helicopter Buttons
865                self.connect(self.pushButtonHelicopterSearch, \
866                                  QtCore.SIGNAL("clicked()"), \
867                                  self.searchForDevices)
868               
869                self.connect(self.pushButtonHelicopterConnect, \
870                                  QtCore.SIGNAL("clicked()"), \
871                                  self.connectToRCHelicopter)
872               
873               
874                self.connect(self.pushButtonHelicopterConcentrationEnable, \
875                                  QtCore.SIGNAL("clicked()"), \
876                                  self.updateHelicopterConcentrationButton)
877               
878                self.connect(self.pushButtonHelicopterRelaxationEnable, \
879                                  QtCore.SIGNAL("clicked()"), \
880                                  self.updateHelicopterRelaxationButton)
881               
882                self.connect(self.pushButtonHelicopterSpeedEnable, \
883                                  QtCore.SIGNAL("clicked()"), \
884                                  self.updateHelicopterSpeedButton)
885               
886               
887                self.connect(self.pushButtonHelicopterHover, \
888                                  QtCore.SIGNAL("clicked()"), \
889                                  self.enableHelicopterHover)
890               
891                self.connect(self.pushButtonHelicopterFlyForward, \
892                                  QtCore.SIGNAL("clicked()"), \
893                                  self.enableHelicopterFlyForward)
894               
895                self.connect(self.pushButtonHelicopterLand, \
896                                  QtCore.SIGNAL("clicked()"), \
897                                  self.landHelicopter)
898               
899               
900               
901                # Wheelchair Buttons
902                self.connect(self.pushButtonWheelchairSearch, \
903                                  QtCore.SIGNAL("clicked()"), \
904                                  self.searchForDevices)
905               
906                self.connect(self.pushButtonWheelchairConnect, \
907                                  QtCore.SIGNAL("clicked()"), \
908                                  self.connectToWheelchair)
909               
910               
911                self.connect(self.pushButtonWheelchairConcentrationEnable, \
912                                  QtCore.SIGNAL("clicked()"), \
913                                  self.updateWheelchairConcentrationButton)
914               
915                self.connect(self.pushButtonWheelchairRelaxationEnable, \
916                                  QtCore.SIGNAL("clicked()"), \
917                                  self.updateWheelchairRelaxationButton)
918               
919                self.connect(self.pushButtonWheelchairSpeedEnable, \
920                                  QtCore.SIGNAL("clicked()"), \
921                                  self.updateWheelchairSpeedButton)
922               
923               
924                self.connect(self.pushButtonWheelchairForward, \
925                                  QtCore.SIGNAL("pressed()"), \
926                                  self.driveWheelchairForward)
927                self.connect(self.pushButtonWheelchairForward, \
928                             QtCore.SIGNAL("released()"), \
929                             self.stopWheelchair)
930               
931                self.connect(self.pushButtonWheelchairReverse, \
932                                  QtCore.SIGNAL("pressed()"), \
933                                  self.driveWheelchairReverse)
934                self.connect(self.pushButtonWheelchairForward, \
935                             QtCore.SIGNAL("released()"), \
936                             self.stopWheelchair)
937               
938                self.connect(self.pushButtonWheelchairLeft, \
939                                  QtCore.SIGNAL("pressed()"), \
940                                  self.driveWheelchairLeft)
941                self.connect(self.pushButtonWheelchairForward, \
942                             QtCore.SIGNAL("released()"), \
943                             self.stopWheelchair)
944               
945                self.connect(self.pushButtonWheelchairRight, \
946                                  QtCore.SIGNAL("pressed()"), \
947                                  self.driveWheelchairRight)
948               
949                self.connect(self.pushButtonWheelchairStop, \
950                                  QtCore.SIGNAL("pressed()"), \
951                                  self.stopWheelchair)
952               
953               
954               
955                # Control Panel Buttons
956                self.connect(self.pushButtonMessageOne, QtCore.SIGNAL("pressed()"), \
957                             self.sendMessageOne)
958               
959                self.connect(self.pushButtonMessageTwo, QtCore.SIGNAL("pressed()"), \
960                             self.sendMessageTwo)
961               
962                self.connect(self.pushButtonMessageThree, QtCore.SIGNAL("pressed()"), \
963                             self.sendMessageThree)
964               
965                self.connect(self.pushButtonMessageFour, QtCore.SIGNAL("pressed()"), \
966                             self.sendMessageFour)
967               
968                self.connect(self.pushButtonMessageFive, QtCore.SIGNAL("pressed()"), \
969                             self.sendMessageFive)
970               
971                self.connect(self.pushButtonMessageSix, QtCore.SIGNAL("pressed()"), \
972                             self.sendMessageSix)
973               
974               
975                self.connect(self.pushButtonThinkGearConnect, \
976                                  QtCore.SIGNAL("clicked()"), \
977                                  self.connectToThinkGearHost)
978               
979                self.connect(self.pushButtonSendFeedback, \
980                                  QtCore.SIGNAL("clicked()"), \
981                                  self.sendFeedback)
982               
983               
984                #shortcut = QtGui.QShortcut(self)
985                #shortcut.setKey(tr("Down"))
986                #self.connect(shortcut, QtCore.SIGNAL("pressed()"), self.driveReverse)
987               
988               
989                action = QtGui.QAction(self)
990                action.setShortcut(QtGui.QKeySequence("W"))
991                self.connect(action, QtCore.SIGNAL("activated()"), self.pushButtonForward, QtCore.SLOT("animateClick()"))
992                self.addAction(action)
993               
994                action = QtGui.QAction(self)
995                action.setShortcut(QtGui.QKeySequence("Up"))
996                self.connect(action, QtCore.SIGNAL("activated()"), self.pushButtonForward, QtCore.SLOT("animateClick()"))
997                self.addAction(action)
998               
999               
1000                action = QtGui.QAction(self)
1001                action.setShortcut(QtGui.QKeySequence("Left"))
1002                self.connect(action, QtCore.SIGNAL("activated()"), self.pushButtonTurnLeft, QtCore.SLOT("animateClick()"))
1003                self.addAction(action)
1004               
1005                action = QtGui.QAction(self)
1006                action.setShortcut(QtGui.QKeySequence("A"))
1007                self.connect(action, QtCore.SIGNAL("activated()"), self.pushButtonTurnLeft, QtCore.SLOT("animateClick()"))
1008                self.addAction(action)
1009               
1010               
1011                action = QtGui.QAction(self)
1012                action.setShortcut(QtGui.QKeySequence("S"))
1013                self.connect(action, QtCore.SIGNAL("activated()"), self.pushButtonReverse, QtCore.SLOT("animateClick()"))
1014                self.addAction(action)
1015               
1016                action = QtGui.QAction(self)
1017                action.setShortcut(QtGui.QKeySequence("Down"))
1018                self.connect(action, QtCore.SIGNAL("activated()"), self.pushButtonReverse, QtCore.SLOT("animateClick()"))
1019                self.addAction(action)
1020               
1021               
1022                action = QtGui.QAction(self)
1023                action.setShortcut(QtGui.QKeySequence("D"))
1024                self.connect(action, QtCore.SIGNAL("activated()"), self.pushButtonTurnRight, QtCore.SLOT("animateClick()"))
1025                self.addAction(action)
1026               
1027                action = QtGui.QAction(self)
1028                action.setShortcut(QtGui.QKeySequence("Right"))
1029                self.connect(action, QtCore.SIGNAL("activated()"), self.pushButtonTurnRight, QtCore.SLOT("animateClick()"))
1030                self.addAction(action)
1031               
1032               
1033                action = QtGui.QAction(self)
1034                action.setShortcut(QtGui.QKeySequence("Z"))
1035                self.connect(action, QtCore.SIGNAL("activated()"), self.pushButtonTurnLeftReverse, QtCore.SLOT("animateClick()"))
1036                self.addAction(action)
1037               
1038               
1039                action = QtGui.QAction(self)
1040                action.setShortcut(QtGui.QKeySequence("C"))
1041                self.connect(action, QtCore.SIGNAL("activated()"), self.pushButtonTurnRightReverse, QtCore.SLOT("animateClick()"))
1042                self.addAction(action)
1043               
1044               
1045               
1046                # RC Helicopter Buttons
1047               
1048                action = QtGui.QAction(self)
1049                action.setShortcut(QtGui.QKeySequence("Home"))
1050                self.connect(action, QtCore.SIGNAL("activated()"), self.pushButtonHelicopterHover, QtCore.SLOT("animateClick()"))
1051                self.addAction(action)
1052                action = QtGui.QAction(self)
1053                action.setShortcut(QtGui.QKeySequence("["))
1054                self.connect(action, QtCore.SIGNAL("activated()"), self.pushButtonHelicopterHover, QtCore.SLOT("animateClick()"))
1055                self.addAction(action)
1056               
1057                action = QtGui.QAction(self)
1058                action.setShortcut(QtGui.QKeySequence("PgUp"))
1059                self.connect(action, QtCore.SIGNAL("activated()"), self.pushButtonHelicopterFlyForward, QtCore.SLOT("animateClick()"))
1060                self.addAction(action)
1061                action = QtGui.QAction(self)
1062                action.setShortcut(QtGui.QKeySequence("]"))
1063                self.connect(action, QtCore.SIGNAL("activated()"), self.pushButtonHelicopterFlyForward, QtCore.SLOT("animateClick()"))
1064                self.addAction(action)
1065               
1066                action = QtGui.QAction(self)
1067                action.setShortcut(QtGui.QKeySequence("End"))
1068                self.connect(action, QtCore.SIGNAL("activated()"), self.pushButtonHelicopterLand, QtCore.SLOT("animateClick()"))
1069                self.addAction(action)
1070                action = QtGui.QAction(self)
1071                action.setShortcut(QtGui.QKeySequence("\\"))
1072                self.connect(action, QtCore.SIGNAL("activated()"), self.pushButtonHelicopterLand, QtCore.SLOT("animateClick()"))
1073                self.addAction(action)
1074               
1075               
1076               
1077                # Wheelchair Buttons
1078               
1079                action = QtGui.QAction(self)
1080                action.setShortcut(QtGui.QKeySequence("i"))
1081                self.connect(action, QtCore.SIGNAL("activated()"), self.pushButtonWheelchairForward, QtCore.SLOT("animateClick()"))
1082                self.addAction(action)
1083               
1084                action = QtGui.QAction(self)
1085                action.setShortcut(QtGui.QKeySequence("k"))
1086                self.connect(action, QtCore.SIGNAL("activated()"), self.pushButtonWheelchairReverse, QtCore.SLOT("animateClick()"))
1087                self.addAction(action)
1088                action = QtGui.QAction(self)
1089                action.setShortcut(QtGui.QKeySequence("m"))
1090                self.connect(action, QtCore.SIGNAL("activated()"), self.pushButtonWheelchairReverse, QtCore.SLOT("animateClick()"))
1091                self.addAction(action)
1092               
1093                action = QtGui.QAction(self)
1094                action.setShortcut(QtGui.QKeySequence("j"))
1095                self.connect(action, QtCore.SIGNAL("activated()"), self.pushButtonWheelchairLeft, QtCore.SLOT("animateClick()"))
1096                self.addAction(action)
1097               
1098                action = QtGui.QAction(self)
1099                action.setShortcut(QtGui.QKeySequence("l"))
1100                self.connect(action, QtCore.SIGNAL("activated()"), self.pushButtonWheelchairRight, QtCore.SLOT("animateClick()"))
1101                self.addAction(action)
1102               
1103                action = QtGui.QAction(self)
1104                action.setShortcut(QtGui.QKeySequence("Space"))
1105                self.connect(action, QtCore.SIGNAL("activated()"), self.pushButtonWheelchairStop, QtCore.SLOT("animateClick()"))
1106                self.addAction(action)
1107               
1108               
1109               
1110                # Control Panel Buttons
1111               
1112                action = QtGui.QAction(self)
1113                action.setShortcut(QtGui.QKeySequence("1"))
1114                self.connect(action, QtCore.SIGNAL("activated()"), self.pushButtonNXTMessageOne, QtCore.SLOT("animateClick()"))
1115                self.addAction(action)
1116               
1117                action = QtGui.QAction(self)
1118                action.setShortcut(QtGui.QKeySequence("2"))
1119                self.connect(action, QtCore.SIGNAL("activated()"), self.pushButtonNXTMessageTwo, QtCore.SLOT("animateClick()"))
1120                self.addAction(action)
1121               
1122                action = QtGui.QAction(self)
1123                action.setShortcut(QtGui.QKeySequence("3"))
1124                self.connect(action, QtCore.SIGNAL("activated()"), self.pushButtonNXTMessageThree, QtCore.SLOT("animateClick()"))
1125                self.addAction(action)
1126               
1127                action = QtGui.QAction(self)
1128                action.setShortcut(QtGui.QKeySequence("4"))
1129                self.connect(action, QtCore.SIGNAL("activated()"), self.pushButtonNXTMessageFour, QtCore.SLOT("animateClick()"))
1130                self.addAction(action)
1131               
1132                action = QtGui.QAction(self)
1133                action.setShortcut(QtGui.QKeySequence("5"))
1134                self.connect(action, QtCore.SIGNAL("activated()"), self.pushButtonNXTMessageFive, QtCore.SLOT("animateClick()"))
1135                self.addAction(action)
1136               
1137                action = QtGui.QAction(self)
1138                action.setShortcut(QtGui.QKeySequence("6"))
1139                self.connect(action, QtCore.SIGNAL("activated()"), self.pushButtonNXTMessageSix, QtCore.SLOT("animateClick()"))
1140                self.addAction(action)
1141               
1142               
1143                #self.pushButtonForward.setAutoRepeat(False)
1144                #self.pushButtonForward.setAutoRepeatDelay(0)
1145                #self.pushButtonForward.setAutoRepeatInterval(0)
1146       
1147       
1148        ##################################################################
1149       
1150        def searchForDevices(self):
1151               
1152                nxt_devices = []
1153                rc_helicopter_devices = []
1154                wheelchair_devices = []
1155               
1156                #if (sys.platform != 'win32'):
1157                if False: # temporarily disabled
1158                       
1159                        # Bluetooth module doesn't compile properly under Windows
1160                       
1161                        bluetooth_devices = []
1162                       
1163                        try:
1164                                bluetooth_devices = bluetooth.discover_devices( \
1165                                                       duration=5, \
1166                                                       flush_cache=True, \
1167                                                       lookup_names=False)
1168                        except:
1169                                #command = '%s con' % PATH_TO_HCITOOL
1170                                command = '%s scan' % PATH_TO_HCITOOL
1171                               
1172                                output = os.popen(command, 'r')
1173                               
1174                                for line in output.readlines():
1175                                        print line
1176                                        try:
1177                                                address = line.split(' ')[2]
1178                                        except:
1179                                                pass
1180                                        else:
1181                                                bluetooth_devices.append(address)
1182                       
1183                        for address in bluetooth_devices:
1184                                device_name = bluetooth.lookup_name(address)
1185                                if ((device_name == 'NXT') and \
1186                                    (address not in nxt_devices)):
1187                                        nxt_devices.append(address)
1188                       
1189                       
1190                        if self.DEBUG:
1191                                print "Bluetooth NXT devices found:",
1192                                print nxt_devices
1193               
1194               
1195                # List all serial devices
1196                serial_devices = self.enumerateSerialPorts()
1197               
1198                for serial_device in serial_devices:
1199                        #serial_device = self.fullPortName(serial_device)
1200                        nxt_devices.append(serial_device)
1201                        rc_helicopter_devices.append(serial_device)
1202                        wheelchair_devices.append(serial_device)
1203               
1204               
1205                # Configure combo boxes
1206                if nxt_devices == []:
1207                        nxt_devices.append('N/A')
1208               
1209                if rc_helicopter_devices == []:
1210                        rc_helicopter_devices.append('N/A')
1211               
1212                if wheelchair_devices == []:
1213                        wheelchair_devices.append('N/A')
1214               
1215               
1216                # Don't reset combo boxes if already connected
1217                if self.pushButtonNXTConnect.text != 'Disconnect':
1218                       
1219                        self.comboBoxNXTPortSelect.clear()
1220                       
1221                        #nxt_devices.reverse()
1222                        for nxt_device in nxt_devices:
1223                                self.comboBoxNXTPortSelect.addItem(nxt_device)
1224               
1225               
1226                if self.pushButtonHelicopterConnect.text != 'Disconnect':
1227                       
1228                        self.comboBoxHelicopterPortSelect.clear()
1229                       
1230                        #rc_helicopter_devices.reverse()
1231                        for rc_helicopter in rc_helicopter_devices:
1232                                self.comboBoxHelicopterPortSelect.addItem(rc_helicopter)
1233       
1234       
1235                if self.pushButtonWheelchairConnect.text != 'Disconnect':
1236                       
1237                        self.comboBoxWheelchairPortSelect.clear()
1238                       
1239                        #rc_helicopter_devices.reverse()
1240                        for wheelchair in wheelchair_devices:
1241                                self.comboBoxWheelchairPortSelect.addItem(wheelchair)
1242       
1243       
1244        ##################################################################
1245       
1246        def enumerateSerialPorts(self):
1247               
1248                """ Uses the Win32 registry to return an
1249                iterator of serial (COM) ports
1250                existing on this computer.
1251               
1252                from http://eli.thegreenplace.net/2009/07/31/listing-all-serial-ports-on-windows-with-python/
1253                """
1254               
1255                serial_ports = []
1256               
1257                if (sys.platform == 'win32'):
1258                       
1259                        path = 'HARDWARE\\DEVICEMAP\\SERIALCOMM'
1260                        try:
1261                                key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, path)
1262                        except WindowsError:
1263                                #raise IterationError
1264                                return []
1265                                #pass
1266                       
1267                        for i in itertools.count():
1268                                try:
1269                                        val = winreg.EnumValue(key, i)
1270                                        #yield str(val[1])
1271                                        serial_ports.append( str(val[1]) )
1272                                except EnvironmentError:
1273                                        break
1274               
1275               
1276                else:
1277                       
1278                        if os.path.exists(DEVICE_PATH):
1279                                device_list = os.listdir(DEVICE_PATH)
1280                               
1281                                device_list.sort()
1282                       
1283                                for device in device_list:
1284                                        if device.startswith('ttyUSB'):
1285                                                serial_ports.append( DEVICE_PATH + '/' + device )
1286                                for device in device_list:
1287                                        if device.startswith('rfcomm'):
1288                                                serial_ports.append( DEVICE_PATH + '/' + device )
1289                                for device in device_list:
1290                                        if device.startswith('ttyACM'):
1291                                                serial_ports.append( DEVICE_PATH + '/' + device )
1292                                for device in device_list:
1293                                        if device.startswith('ttyS'):
1294                                                serial_ports.append( DEVICE_PATH + '/' + device )
1295               
1296               
1297                return(serial_ports)
1298       
1299       
1300        ##################################################################
1301       
1302        def fullPortName(self, portname):
1303               
1304                """ Given a port-name (of the form COM7,
1305                COM12, CNCA0, etc.) returns a full
1306                name suitable for opening with the
1307                Serial class.
1308                """
1309               
1310                m = re.match('^COM(\d+)$', portname)
1311                if m and int(m.group(1)) < 10:
1312                        return portname
1313               
1314                return '\\\\.\\' + portname
1315       
1316       
1317        ##################################################################
1318       
1319        # LEGO Mindstorms Controls
1320       
1321        def turnLeft(self):
1322                self.brainstormsClient.sendCommand('turn_left')
1323                self.drive_state = 'turn_left'
1324       
1325        def driveForward(self):
1326                #if self.DEBUG:
1327                        #print "driveForward"
1328                self.pushButtonForward.setDown(True)
1329                if (self.drive_state != 'drive_forward'):
1330                        self.updateNXTSpeed(new_speed=DEFAULT_NXT_POWER_LEVEL)
1331                self.brainstormsClient.sendCommand('drive_forward', power=self.current_speed)
1332                self.drive_state = 'drive_forward'
1333       
1334        def turnRight(self):
1335                self.brainstormsClient.sendCommand('turn_right')
1336                self.drive_state = 'turn_right'
1337       
1338        def turnLeftInReverse(self):
1339                self.brainstormsClient.sendCommand('turn_left_in_reverse')
1340                self.drive_state = 'turn_left_in_reverse'
1341       
1342        def driveReverse(self):
1343                self.brainstormsClient.sendCommand('drive_reverse')
1344                self.drive_state = 'drive_reverse'
1345       
1346        def turnRightInReverse(self):
1347                self.brainstormsClient.sendCommand('turn_right_in_reverse')
1348                self.drive_state = 'turn_right_in_reverse'
1349       
1350        def stopMotors(self):
1351                self.pushButtonForward.setDown(False)
1352                if (self.current_speed != 0):
1353                        self.updateNXTSpeed(new_speed=0)
1354                if self.brainstormsClient != None:
1355                        self.brainstormsClient.sendCommand('stop_motors')
1356                self.drive_state = 'stop_motors'
1357       
1358        def sendMessageOne(self):
1359                message = str(self.lineEditMessageOne.text())
1360                self.brainstormsClient.sendCommand('send_message_1')
1361       
1362        def sendMessageTwo(self):
1363                message = str(self.lineEditMessageTwo.text())
1364                self.brainstormsClient.sendCommand('send_message_2')
1365       
1366        def sendMessageThree(self):
1367                message = str(self.lineEditMessageThree.text())
1368                self.brainstormsClient.sendCommand('send_message_3')
1369       
1370        def sendMessageFour(self):
1371                message = str(self.lineEditMessageFour.text())
1372                self.brainstormsClient.sendCommand('send_message_4')
1373       
1374        def sendMessageFive(self):
1375                message = str(self.lineEditMessageFive.text())
1376                self.brainstormsClient.sendCommand('send_message_5')
1377       
1378        def sendMessageSix(self):
1379                message = str(self.lineEditMessageSix.text())
1380                self.brainstormsClient.sendCommand('send_message_6')
1381       
1382       
1383        ##################################################################
1384       
1385        def enableHelicopterHover(self):
1386               
1387                if self.pushButtonHelicopterFlyForward.isChecked():
1388                        self.pushButtonHelicopterFlyForward.setChecked(False)
1389                        self.disableHelicopterFlyForward()
1390               
1391                self.helicopter.hover(duration=None)
1392                self.current_helicopter_state = 'hover'
1393               
1394                self.disconnect(self.pushButtonHelicopterHover, \
1395                                                        QtCore.SIGNAL("clicked()"), \
1396                                                        self.enableHelicopterHover)
1397               
1398                self.connect(self.pushButtonHelicopterHover, \
1399                                  QtCore.SIGNAL("clicked()"), \
1400                                  self.disableHelicopterHover)
1401               
1402                #if self.pushButtonHelicopterFlyForward.isChecked():
1403                        #self.pushButtonHelicopterFlyForward.toggle()
1404                        ##self.disableHelicopterFlyForward()
1405       
1406       
1407        ##################################################################
1408       
1409        def disableHelicopterHover(self):
1410               
1411                self.helicopter.neutral()
1412                self.current_helicopter_state = 'neutral'
1413               
1414                self.disconnect(self.pushButtonHelicopterHover, \
1415                                                        QtCore.SIGNAL("clicked()"), \
1416                                                        self.disableHelicopterHover)
1417               
1418                self.connect(self.pushButtonHelicopterHover, \
1419                                  QtCore.SIGNAL("clicked()"), \
1420                                  self.enableHelicopterHover)
1421       
1422       
1423        ##################################################################
1424       
1425        def enableHelicopterFlyForward(self):
1426               
1427                if self.pushButtonHelicopterHover.isChecked():
1428                        self.pushButtonHelicopterHover.setChecked(False)
1429                        self.disableHelicopterHover()
1430               
1431                self.helicopter.fly_forward(duration=None)
1432                self.current_helicopter_state = 'fly_forward'
1433               
1434                self.disconnect(self.pushButtonHelicopterFlyForward, \
1435                                                        QtCore.SIGNAL("clicked()"), \
1436                                                        self.enableHelicopterFlyForward)
1437               
1438                self.connect(self.pushButtonHelicopterFlyForward, \
1439                                  QtCore.SIGNAL("clicked()"), \
1440                                  self.disableHelicopterFlyForward)
1441               
1442                #if self.pushButtonHelicopterHover.isChecked():
1443                        #self.pushButtonHelicopterHover.toggle()
1444                        ##self.disableHelicopterHover()
1445       
1446       
1447        ##################################################################
1448       
1449        def disableHelicopterFlyForward(self):
1450               
1451                self.helicopter.neutral()
1452                self.current_helicopter_state = 'neutral'
1453               
1454                self.disconnect(self.pushButtonHelicopterFlyForward, \
1455                                                        QtCore.SIGNAL("clicked()"), \
1456                                                        self.disableHelicopterFlyForward)
1457               
1458                self.connect(self.pushButtonHelicopterFlyForward, \
1459                                  QtCore.SIGNAL("clicked()"), \
1460                                  self.enableHelicopterFlyForward)
1461       
1462       
1463        ##################################################################
1464       
1465        def landHelicopter(self):
1466               
1467                self.helicopter.neutral()
1468                self.current_helicopter_state = 'neutral'
1469               
1470                if self.pushButtonHelicopterHover.isChecked():
1471                        self.pushButtonHelicopterHover.setChecked(False)
1472                        self.disableHelicopterHover()
1473                if self.pushButtonHelicopterFlyForward.isChecked():
1474                        self.pushButtonHelicopterFlyForward.setChecked(False)
1475                        self.disableHelicopterFlyForward()
1476       
1477       
1478        ##################################################################
1479       
1480        def driveWheelchairForward(self):
1481                #print "WheelchairForward"
1482                speed = self.dialWheelchairSpeed.value()
1483                self.wheelchair.sendCommand(speed, 'forward')
1484       
1485        def driveWheelchairReverse(self):
1486                print "WheelchairReverse"
1487                speed = self.dialWheelchairSpeed.value()
1488                self.wheelchair.sendCommand(speed, 'reverse')
1489       
1490        def driveWheelchairLeft(self):
1491                print "WheelchairLeft"
1492                speed = self.dialWheelchairSpeed.value()
1493                self.wheelchair.sendCommand(speed, 'left')
1494       
1495        def driveWheelchairRight(self):
1496                print "WheelchairRight"
1497                speed = self.dialWheelchairSpeed.value()
1498                self.wheelchair.sendCommand(speed, 'right')
1499       
1500        def stopWheelchair(self):
1501                print "stopWheelchair"
1502                speed = self.dialWheelchairSpeed.value()
1503                self.wheelchair.sendCommand(speed, 'stop')
1504       
1505       
1506        ##################################################################
1507       
1508        def updateNXTSpeed(self, new_speed=None):
1509               
1510                if new_speed == None:
1511               
1512                        concentration=self.progressBarConcentration.value()
1513                        relaxation=self.progressBarRelaxation.value()
1514                       
1515                        new_speed = self.calculateSpeed(concentration, relaxation)
1516               
1517               
1518                # Update GUI
1519                if self.pushButtonSpeedEnable.isChecked():
1520                        self.progressBarSpeed.setValue(new_speed)
1521               
1522               
1523                # If there is a change between the new and current speeds
1524                # and either the robot is currently driving forward
1525                # or the "speed control" button is enabled,
1526                # then send the updated speed to the robot
1527                if ((self.current_speed != new_speed) and \
1528                         ((self.drive_state == 'drive_forward') or \
1529                          (self.pushButtonSpeedEnable.isChecked()))):
1530                       
1531                        if (new_speed == 0):
1532                                self.current_speed = new_speed
1533                                self.stopMotors()
1534                        else:
1535                                if ((self.brainstormsClient != None) and \
1536                                    (self.pushButtonSpeedEnable.isChecked())):
1537                                        self.pushButtonForward.setDown(True)
1538                                        self.brainstormsClient.sendCommand('drive_forward', power=new_speed)
1539               
1540               
1541                self.current_speed = new_speed
1542       
1543       
1544        ##################################################################
1545       
1546        def updateHelicopterSpeed(self, new_speed=None):
1547               
1548                if new_speed == None:
1549               
1550                        concentration=self.progressBarHelicopterConcentration.value()
1551                        relaxation=self.progressBarHelicopterRelaxation.value()
1552                       
1553                        new_speed = self.calculateSpeed(concentration, relaxation)
1554               
1555               
1556                # Update GUI
1557                if self.pushButtonHelicopterSpeedEnable.isChecked():
1558                        self.progressBarHelicopterSpeed.setValue(new_speed)
1559                       
1560                        if ((new_speed > 0) and \
1561                            (self.current_helicopter_state == 'neutral') and \
1562                            (self.helicopter != None)):
1563                                self.enableHelicopterHover()
1564                       
1565                        elif ((new_speed == 0) and \
1566                              (self.current_helicopter_state != 'neutral') and \
1567                              (self.helicopter != None)):
1568                                self.landHelicopter()
1569               
1570               
1571                self.current_speed = new_speed
1572       
1573       
1574        ##################################################################
1575       
1576        def updateWheelchairSpeed(self, new_speed=None):
1577               
1578                if new_speed == None:
1579               
1580                        concentration=self.progressBarWheelchairConcentration.value()
1581                        relaxation=self.progressBarWheelchairRelaxation.value()
1582                       
1583                        new_speed = self.calculateSpeed(concentration, relaxation)
1584               
1585               
1586                # Update GUI
1587                if self.pushButtonWheelchairSpeedEnable.isChecked():
1588                        self.progressBarWheelchairSpeed.setValue(new_speed)
1589               
1590               
1591                self.current_speed = new_speed
1592       
1593       
1594        ##################################################################
1595       
1596        def calculateSpeed(self, concentration, relaxation):
1597               
1598                speed = 0
1599               
1600                thresholds = THINKGEAR_POWER_THRESHOLDS
1601               
1602                match = int(concentration)
1603               
1604                while ((match not in thresholds['concentration'].keys()) and \
1605                            (match >= 0)):
1606                        match -= 1
1607               
1608               
1609                if match in thresholds['concentration'].keys():
1610                        speed = thresholds['concentration'][match]
1611               
1612               
1613                match = int(relaxation)
1614               
1615                while ((match not in thresholds['relaxation'].keys()) and \
1616                            (match >= 0)):
1617                        match -= 1
1618               
1619                if match in thresholds['relaxation'].keys():
1620                        speed = speed + thresholds['relaxation'][match]
1621               
1622               
1623                # LEGO Mindstorms power settings cannot exceed 100
1624                # and don't drive well with levels less than 50
1625                if (speed > 100):
1626                        speed = 100
1627                elif (speed < 50):
1628                        speed = 0
1629               
1630               
1631                return(speed)
1632       
1633       
1634        ##################################################################
1635       
1636        def processPacketThinkGear(self, packet):
1637               
1638                if ('eSense' in packet.keys()):
1639                       
1640                        if ('attention' in packet['eSense'].keys()):
1641                                if self.pushButtonConcentrationEnable.isChecked():
1642                                        self.progressBarConcentration.setValue(packet['eSense']['attention'])
1643                                if self.pushButtonHelicopterConcentrationEnable.isChecked():
1644                                        self.progressBarHelicopterConcentration.setValue(packet['eSense']['attention'])
1645                                if self.pushButtonWheelchairConcentrationEnable.isChecked():
1646                                        self.progressBarWheelchairConcentration.setValue(packet['eSense']['attention'])
1647                       
1648                        if ('meditation' in packet['eSense'].keys()):
1649                                if self.pushButtonRelaxationEnable.isChecked():
1650                                        self.progressBarRelaxation.setValue(packet['eSense']['meditation'])
1651                                if self.pushButtonHelicopterRelaxationEnable.isChecked():
1652                                        self.progressBarHelicopterRelaxation.setValue(packet['eSense']['meditation'])
1653                                if self.pushButtonWheelchairRelaxationEnable.isChecked():
1654                                        self.progressBarWheelchairRelaxation.setValue(packet['eSense']['meditation'])
1655               
1656               
1657                self.updateNXTSpeed()
1658                self.updateHelicopterSpeed()
1659                self.updateWheelchairSpeed()
1660       
1661       
1662        ##################################################################
1663
1664        def sendFeedback(self):
1665               
1666                values = {}
1667
1668                values['name'] = str(self.lineEditFeedbackName.text())
1669                values['email'] = str(self.lineEditFeedbackEmail.text())
1670                values['comment'] = str(self.textEditFeedback.toPlainText())
1671               
1672                values['subject'] = '[brainstorms feedback]'
1673                values['capcha_contact'] = 'brainstorms'
1674               
1675               
1676                url_data = urllib.urlencode(values)
1677               
1678                try:
1679                        page = urllib.urlopen(BRAINSTORMS_FEEDBACK_URL, url_data)
1680                       
1681                        reply = QtGui.QMessageBox.information( \
1682                              self, \
1683                              'Feedback Sent', \
1684                              'Thank you for your feedback', \
1685                              'OK')
1686                       
1687                        self.lineEditFeedbackName.setText('')
1688                        self.lineEditFeedbackEmail.setText('')
1689                        self.textEditFeedback.setText('')
1690               
1691                except:
1692                        reply = QtGui.QMessageBox.information( \
1693                              self, \
1694                              'Feedback Sent', \
1695                              'We\'re sorry but there was an error submitting your feedback.\nPlease email contact@puzzlebox.info instead.', \
1696                              'OK')
1697       
1698       
1699        ##################################################################
1700       
1701        def closeEvent(self, event):
1702               
1703                quit_message = "Are you sure you want to exit the program?"
1704               
1705                reply = QtGui.QMessageBox.question( \
1706                           self, \
1707                          'Quit Puzzlebox Brainstorms', \
1708                           quit_message, \
1709                           QtGui.QMessageBox.Yes, \
1710                           QtGui.QMessageBox.No)
1711               
1712                if reply == QtGui.QMessageBox.Yes:
1713                       
1714                        if self.brainstormsClient != None:
1715                                self.stopMotors()
1716                                self.brainstormsClient.socket.flush()
1717                               
1718                                if self.brainstormsServer != None:
1719                                       
1720                                        if self.brainstormsServer.rc == None:
1721                                               
1722                                                bluetooth_device = str(self.comboBoxNXTPortSelect.currentText())
1723                                                self.brainstormsServer.executeCommand( \
1724                                                        'stop_motors', \
1725                                                        bluetooth_device=bluetooth_device)
1726                                               
1727                                        else:
1728                                                self.brainstormsServer.rc.run('stop_motors')
1729                       
1730                       
1731                        event.accept()
1732               
1733                else:
1734                        event.ignore()
1735
1736
1737#####################################################################
1738# Functions
1739#####################################################################
1740
1741#####################################################################
1742# Main
1743#####################################################################
1744
1745if __name__ == '__main__':
1746       
1747        #log = puzzlebox_logger.puzzlebox_logger(logfile='client_interface')
1748        log = None
1749       
1750        app = QtGui.QApplication(sys.argv)
1751       
1752        window = puzzlebox_brainstorms_client_interface(log, DEBUG)
1753        window.show()
1754       
1755        sys.exit(app.exec_())
1756
Note: See TracBrowser for help on using the repository browser.