source: remote_control/puzzlebox_brainstorms_client_interface.py @ 108

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

remote_control/puzzlebox_brainstorms_network_client.py:

  • voltage display fix

remote_control/puzzlebox_brainstorms_configuration:

  • system based defaults for NXT Bluetooth device

remote_control/puzzlebox_brainstorms_client_interface.py:

  • user define NXT Bluetooth device support added

remote_control/puzzlebox_brainstorms_network_server.py:

  • user define NXT Bluetooth device support fixed
File size: 16.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# Last Update: 2010.07.10
12#
13#####################################################################
14# To Do:
15# - server may not correctly handle multiple clients connected
16#      to an embedded Brainstorms server
17# - disable autorepeating on shortcut keys
18# - update configuration.ini file with settings entered into interface
19#####################################################################
20
21import os, sys
22
23#try:
24        #from PySide import QtCore, QtGui, QtNetwork
25#except:
26        #print "Using PyQt4 module"
27        #from PyQt4 import QtCore, QtGui, QtNetwork
28#else:
29        #print "Using PySide module"
30
31from PyQt4 import QtCore, QtGui, QtNetwork
32#from PySide import QtCore, QtGui, QtNetwork
33
34from puzzlebox_brainstorms_client_interface_design import Ui_Form
35
36import simplejson as json
37
38import puzzlebox_brainstorms_configuration as configuration
39import puzzlebox_brainstorms_network_client as brainstorms_client
40import puzzlebox_brainstorms_network_client_thinkgear as thinkgear_client
41#import puzzlebox_logger
42
43#####################################################################
44# Globals
45#####################################################################
46
47DEBUG = 1
48
49THINKGEAR_POWER_THRESHOLDS = configuration.THINKGEAR_POWER_THRESHOLDS
50
51BLUETOOTH_DEVICE = configuration.NXT_BLUETOOTH_DEVICE
52
53NXT_BLUETOOTH_DEVICE = configuration.NXT_BLUETOOTH_DEVICE
54
55DEFAULT_NXT_POWER_LEVEL = configuration.DEFAULT_NXT_POWER_LEVEL
56
57THINKGEAR_SERVER_HOST = configuration.THINKGEAR_SERVER_HOST
58THINKGEAR_SERVER_PORT = configuration.THINKGEAR_SERVER_PORT
59
60#####################################################################
61# Classes
62#####################################################################
63
64class puzzlebox_brainstorms_client_interface(QtGui.QWidget, Ui_Form):
65       
66        def __init__(self, log, DEBUG=DEBUG, parent = None):
67               
68                self.log = log
69                self.DEBUG = DEBUG
70               
71                QtGui.QWidget.__init__(self, parent)
72                self.setupUi(self)
73               
74                self.configureSettings()
75                self.connectWidgets()
76               
77                self.brainstormsClient = None
78               
79                self.drive_state = 'stop_motors'
80                self.current_speed = 0
81       
82       
83        ##################################################################
84       
85        def configureSettings(self):
86               
87                # Brainstorms Interface
88               
89                icon = QtGui.QIcon()
90                icon.addPixmap(QtGui.QPixmap("images/puzzlebox.ico"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
91                self.setWindowIcon(icon)
92               
93                self.pushButtonTurnLeft.setEnabled(False)
94                self.pushButtonForward.setEnabled(False)
95                self.pushButtonTurnRight.setEnabled(False)
96                self.pushButtonTurnLeftReverse.setEnabled(False)
97                self.pushButtonReverse.setEnabled(False)
98                self.pushButtonTurnRightReverse.setEnabled(False)
99               
100               
101                # LEGO Mindstorms
102               
103                self.textLabelNXTStatus.setText("Status: Disconnected")
104               
105                # Display communication port for LEGO Mindstorms NXT device
106                self.lineEditNXTPort.setText(NXT_BLUETOOTH_DEVICE)
107                self.lineEditNXTPort.setEnabled(True)
108               
109               
110                # EEG Headset
111               
112                # Display Host for ThinkGear Connect Socket Server
113                self.lineEditThinkGearHost.setText(THINKGEAR_SERVER_HOST)
114                #self.lineEditThinkGearHost.setEnabled(False)
115               
116                # Display Port for ThinkGear Connect Socket Server
117                self.lineEditThinkGearPort.setText('%i' % THINKGEAR_SERVER_PORT)
118                #self.lineEditThinkGearPort.setEnabled(False)
119       
120       
121        ##################################################################
122       
123        def getMinimumThreshold(self, threshold):
124               
125                '''Return the minimum detection level which results
126                in a non-zero power setting'''
127               
128                minimum = 100
129               
130                threshold_keys = threshold.keys()
131                threshold_keys.sort()
132                threshold_keys.reverse()
133               
134                for key in threshold_keys:
135                       
136                        if ((threshold[key] < minimum) and \
137                                 (threshold[key] > 0)):
138                                minimum = key
139               
140               
141                return(minimum)
142       
143       
144        ##################################################################
145       
146        def configureNetworkBrainstorms(self):
147               
148                bluetooth_device = self.lineEditNXTPort.text()
149               
150                self.brainstormsClient = \
151                   brainstorms_client.puzzlebox_brainstorms_network_client( \
152                           self.log, \
153                           bluetooth_device=bluetooth_device, \
154                           parent=self)
155               
156                self.brainstormsClient.sendCommand('connect', \
157                                                   bluetooth_device=bluetooth_device)
158       
159       
160        ##################################################################
161       
162        def connectToBrainstormsServer(self):
163               
164                if self.DEBUG:
165                        print "Connecting to Brainstorms Server"
166               
167                #server_port = int(self.lineEditNXTPort.text())
168               
169                self.configureNetworkBrainstorms()
170               
171                #if (self.brainstormsClient.socket.state() != QtNetwork.QAbstractSocket.ConnectedState):
172                        #QtGui.QMessageBox.information(self, \
173                                                                #self.brainstormsClient.socket.name, \
174                                           #"Failed to connect to Brainstorms socket server")
175               
176                #else:
177                self.disconnect(self.pushButtonNXTConnect, \
178                                                        QtCore.SIGNAL("clicked()"), \
179                                                        self.connectToBrainstormsServer)
180               
181                self.connect(self.pushButtonNXTConnect, \
182                                                        QtCore.SIGNAL("clicked()"), \
183                                                        self.disconnectFromBrainstormsServer)
184               
185                self.textLabelNXTStatus.setText("Status: Connected")
186                self.pushButtonNXTConnect.setText('Disconnect')
187               
188                self.lineEditNXTPort.setEnabled(False)
189               
190                self.pushButtonTurnLeft.setEnabled(True)
191                self.pushButtonForward.setEnabled(True)
192                self.pushButtonTurnRight.setEnabled(True)
193                self.pushButtonTurnLeftReverse.setEnabled(True)
194                self.pushButtonReverse.setEnabled(True)
195                self.pushButtonTurnRightReverse.setEnabled(True)
196       
197       
198        ##################################################################
199       
200        def disconnectFromBrainstormsServer(self):
201               
202                if self.DEBUG:
203                        print "Disconnecting from Brainstorms Server"
204               
205                self.brainstormsClient.socket.disconnectFromHost()
206               
207                self.disconnect(self.pushButtonNXTConnect, \
208                                  QtCore.SIGNAL("clicked()"), \
209                                  self.disconnectFromBrainstormsServer)
210               
211                self.connect(self.pushButtonNXTConnect, \
212                                  QtCore.SIGNAL("clicked()"), \
213                                  self.connectToBrainstormsServer)
214               
215                self.textLabelNXTStatus.setText("Status: Disconnected")
216                self.pushButtonNXTConnect.setText('Connect')
217               
218                self.lineEditNXTPort.setEnabled(True)
219               
220                self.pushButtonTurnLeft.setEnabled(False)
221                self.pushButtonForward.setEnabled(False)
222                self.pushButtonTurnRight.setEnabled(False)
223                self.pushButtonTurnLeftReverse.setEnabled(False)
224                self.pushButtonReverse.setEnabled(False)
225                self.pushButtonTurnRightReverse.setEnabled(False)
226               
227                self.brainstormsClient = None
228       
229       
230        ##################################################################
231       
232        def connectToThinkGearHost(self):
233               
234                if self.DEBUG:
235                        print "Connecting to ThinkGear Host"
236               
237                server_host = str(self.lineEditThinkGearHost.text())
238                server_port = int(self.lineEditThinkGearPort.text())
239               
240                self.thinkgearClient = \
241                   thinkgear_client.puzzlebox_brainstorms_network_client_thinkgear( \
242                           self.log, \
243                           server_host=server_host, \
244                           server_port=server_port, \
245                           DEBUG=0, \
246                           parent=self)
247               
248                if (self.thinkgearClient.socket.state() != QtNetwork.QAbstractSocket.ConnectedState):
249                        QtGui.QMessageBox.information(self, \
250                                                                self.thinkgearClient.socket.name, \
251                                           "Failed to connect to ThinkGear socket server")
252               
253                else:
254                        self.disconnect(self.pushButtonThinkGearConnect, \
255                                                         QtCore.SIGNAL("clicked()"), \
256                                                         self.connectToThinkGearHost)
257                       
258                        self.connect(self.pushButtonThinkGearConnect, \
259                                                         QtCore.SIGNAL("clicked()"), \
260                                                         self.disconnectFromThinkGearHost)
261                       
262                        self.pushButtonThinkGearConnect.setText('Disconnect')
263                       
264                        self.lineEditThinkGearHost.setEnabled(False)
265                        self.lineEditThinkGearPort.setEnabled(False)
266       
267       
268        ##################################################################
269       
270        def disconnectFromThinkGearHost(self):
271               
272                if self.DEBUG:
273                        print "Disconnecting from ThinkGear Host"
274               
275                self.thinkgearClient.disconnectFromHost()
276               
277                self.disconnect(self.pushButtonThinkGearConnect, \
278                                  QtCore.SIGNAL("clicked()"), \
279                                  self.disconnectFromThinkGearHost)
280               
281                self.connect(self.pushButtonThinkGearConnect, \
282                                  QtCore.SIGNAL("clicked()"), \
283                                  self.connectToThinkGearHost)
284               
285                self.pushButtonForward.emit(QtCore.SIGNAL("released()"))
286               
287                self.pushButtonThinkGearConnect.setText('Connect')
288               
289                self.lineEditThinkGearHost.setEnabled(True)
290                self.lineEditThinkGearPort.setEnabled(True)
291               
292                self.progressBarConcentration.setValue(0)
293                self.progressBarRelaxation.setValue(0)
294                self.progressBarSpeed.setValue(0)
295       
296       
297        ##################################################################
298       
299        def connectWidgets(self):
300               
301                self.connect(self.pushButtonTurnLeft, QtCore.SIGNAL("pressed()"), \
302                             self.turnLeft)
303                self.connect(self.pushButtonTurnLeft, QtCore.SIGNAL("released()"), \
304                             self.stopMotors)
305               
306                self.connect(self.pushButtonForward, QtCore.SIGNAL("pressed()"), \
307                             self.driveForward)
308                self.connect(self.pushButtonForward, QtCore.SIGNAL("released()"), \
309                             self.stopMotors)
310               
311                self.connect(self.pushButtonTurnRight, QtCore.SIGNAL("pressed()"), \
312                             self.turnRight)
313                self.connect(self.pushButtonTurnRight, QtCore.SIGNAL("released()"), \
314                             self.stopMotors)
315               
316                self.connect(self.pushButtonTurnLeftReverse, QtCore.SIGNAL("pressed()"), \
317                             self.turnLeftInReverse)
318                self.connect(self.pushButtonTurnLeftReverse, QtCore.SIGNAL("released()"), \
319                             self.stopMotors)
320               
321                self.connect(self.pushButtonReverse, QtCore.SIGNAL("pressed()"), \
322                             self.driveReverse)
323                self.connect(self.pushButtonReverse, QtCore.SIGNAL("released()"), \
324                             self.stopMotors)
325               
326                self.connect(self.pushButtonTurnRightReverse, QtCore.SIGNAL("pressed()"), \
327                             self.turnRightInReverse)
328                self.connect(self.pushButtonTurnRightReverse, QtCore.SIGNAL("released()"), \
329                             self.stopMotors)
330               
331               
332                self.connect(self.pushButtonNXTConnect, \
333                                  QtCore.SIGNAL("clicked()"), \
334                                  self.connectToBrainstormsServer)
335               
336                self.connect(self.pushButtonThinkGearConnect, \
337                                  QtCore.SIGNAL("clicked()"), \
338                                  self.connectToThinkGearHost)
339               
340               
341                #shortcut = QtGui.QShortcut(self)
342                #shortcut.setKey(tr("Down"))
343                #self.connect(shortcut, QtCore.SIGNAL("pressed()"), self.driveReverse)
344               
345               
346                action = QtGui.QAction(self)
347                action.setShortcut(QtGui.QKeySequence("W"))
348                self.connect(action, QtCore.SIGNAL("activated()"), self.pushButtonForward, QtCore.SLOT("animateClick()"))
349                self.addAction(action)
350               
351                action = QtGui.QAction(self)
352                action.setShortcut(QtGui.QKeySequence("Up"))
353                self.connect(action, QtCore.SIGNAL("activated()"), self.pushButtonForward, QtCore.SLOT("animateClick()"))
354                self.addAction(action)
355               
356               
357                action = QtGui.QAction(self)
358                action.setShortcut(QtGui.QKeySequence("Left"))
359                self.connect(action, QtCore.SIGNAL("activated()"), self.pushButtonTurnLeft, QtCore.SLOT("animateClick()"))
360                self.addAction(action)
361               
362                action = QtGui.QAction(self)
363                action.setShortcut(QtGui.QKeySequence("A"))
364                self.connect(action, QtCore.SIGNAL("activated()"), self.pushButtonTurnLeft, QtCore.SLOT("animateClick()"))
365                self.addAction(action)
366               
367               
368                action = QtGui.QAction(self)
369                action.setShortcut(QtGui.QKeySequence("S"))
370                self.connect(action, QtCore.SIGNAL("activated()"), self.pushButtonReverse, QtCore.SLOT("animateClick()"))
371                self.addAction(action)
372               
373                action = QtGui.QAction(self)
374                action.setShortcut(QtGui.QKeySequence("Down"))
375                self.connect(action, QtCore.SIGNAL("activated()"), self.pushButtonReverse, QtCore.SLOT("animateClick()"))
376                self.addAction(action)
377               
378               
379                action = QtGui.QAction(self)
380                action.setShortcut(QtGui.QKeySequence("D"))
381                self.connect(action, QtCore.SIGNAL("activated()"), self.pushButtonTurnRight, QtCore.SLOT("animateClick()"))
382                self.addAction(action)
383               
384                action = QtGui.QAction(self)
385                action.setShortcut(QtGui.QKeySequence("Right"))
386                self.connect(action, QtCore.SIGNAL("activated()"), self.pushButtonTurnRight, QtCore.SLOT("animateClick()"))
387                self.addAction(action)
388               
389               
390                action = QtGui.QAction(self)
391                action.setShortcut(QtGui.QKeySequence("Z"))
392                self.connect(action, QtCore.SIGNAL("activated()"), self.pushButtonTurnLeftReverse, QtCore.SLOT("animateClick()"))
393                self.addAction(action)
394               
395               
396                action = QtGui.QAction(self)
397                action.setShortcut(QtGui.QKeySequence("C"))
398                self.connect(action, QtCore.SIGNAL("activated()"), self.pushButtonTurnRightReverse, QtCore.SLOT("animateClick()"))
399                self.addAction(action)
400               
401               
402                #self.pushButtonForward.setAutoRepeat(False)
403                #self.pushButtonForward.setAutoRepeatDelay(0)
404                #self.pushButtonForward.setAutoRepeatInterval(0)
405
406       
407        ##################################################################
408       
409        def turnLeft(self):
410                self.brainstormsClient.sendCommand('turn_left')
411                self.drive_state = 'turn_left'
412       
413        def driveForward(self):
414                #if self.DEBUG:
415                        #print "driveForward"
416                self.pushButtonForward.setDown(True)
417                if (self.drive_state != 'drive_forward'):
418                        self.updateSpeed(new_speed=DEFAULT_NXT_POWER_LEVEL)
419                self.brainstormsClient.sendCommand('drive_forward', power=self.current_speed)
420                self.drive_state = 'drive_forward'
421       
422        def turnRight(self):
423                self.brainstormsClient.sendCommand('turn_right')
424                self.drive_state = 'turn_right'
425       
426        def turnLeftInReverse(self):
427                self.brainstormsClient.sendCommand('turn_left_in_reverse')
428                self.drive_state = 'turn_left_in_reverse'
429       
430        def driveReverse(self):
431                self.brainstormsClient.sendCommand('drive_reverse')
432                self.drive_state = 'drive_reverse'
433       
434        def turnRightInReverse(self):
435                self.brainstormsClient.sendCommand('turn_right_in_reverse')
436                self.drive_state = 'turn_right_in_reverse'
437       
438        def stopMotors(self):
439                self.pushButtonForward.setDown(False)
440                if (self.current_speed != 0):
441                        self.updateSpeed(new_speed=0)
442                if self.brainstormsClient != None:
443                        self.brainstormsClient.sendCommand('stop_motors')
444                self.drive_state = 'stop_motors'
445       
446       
447        ##################################################################
448       
449        def updateSpeed(self, new_speed=None):
450               
451                if new_speed == None:
452               
453                        concentration=self.progressBarConcentration.value()
454                        relaxation=self.progressBarRelaxation.value()
455                       
456                        new_speed = self.calculateSpeed(concentration, relaxation)
457               
458               
459                # Update GUI
460                self.progressBarSpeed.setValue(new_speed)
461               
462                # GUI button under "Speed" progress bar set to Enabled
463                speed_control = (self.pushButtonSpeedEnable.text() == 'Enabled')
464               
465                # If there is a change between the new and current speeds
466                # and either the robot is currently driving forward
467                # or the "speed control" button is enabled,
468                # then send the updated speed to the robot
469                if ((self.current_speed != new_speed) and \
470                         ((self.drive_state == 'drive_forward') or \
471                          (speed_control))):
472                       
473                        if (new_speed == 0):
474                                self.current_speed = new_speed
475                                self.stopMotors()
476                        else:
477                                if self.brainstormsClient != None:
478                                        self.pushButtonForward.setDown(True)
479                                        self.brainstormsClient.sendCommand('drive_forward', power=new_speed)
480               
481               
482                self.current_speed = new_speed
483       
484       
485        ##################################################################
486       
487        def calculateSpeed(self, concentration, relaxation):
488               
489                speed = 0
490               
491                thresholds = THINKGEAR_POWER_THRESHOLDS
492               
493                match = int(concentration)
494               
495                while ((match not in thresholds['concentration'].keys()) and \
496                            (match >= 0)):
497                        match -= 1
498               
499               
500                if match in thresholds['concentration'].keys():
501                        speed = thresholds['concentration'][match]
502               
503               
504                match = int(relaxation)
505               
506                while ((match not in thresholds['relaxation'].keys()) and \
507                            (match >= 0)):
508                        match -= 1
509               
510                if match in thresholds['relaxation'].keys():
511                        speed = speed + thresholds['relaxation'][match]
512               
513               
514                # LEGO Mindstorms power settings cannot exceed 100
515                # and don't drive well with levels less than 50
516                if (speed > 100):
517                        speed = 100
518                elif (speed < 50):
519                        speed = 0
520               
521               
522                return(speed)
523       
524       
525        ##################################################################
526       
527        def processPacketThinkGear(self, packet):
528               
529                if ('eSense' in packet.keys()):
530                       
531                        if ('attention' in packet['eSense'].keys()):
532                                self.progressBarConcentration.setValue(packet['eSense']['attention'])
533                       
534                        if ('meditation' in packet['eSense'].keys()):
535                                self.progressBarRelaxation.setValue(packet['eSense']['meditation'])
536               
537               
538                self.updateSpeed()
539
540
541#####################################################################
542# Functions
543#####################################################################
544
545#####################################################################
546# Main
547#####################################################################
548
549if __name__ == '__main__':
550       
551        #log = puzzlebox_logger.puzzlebox_logger(logfile='client_interface')
552        log = None
553       
554        app = QtGui.QApplication(sys.argv)
555       
556        window = puzzlebox_brainstorms_client_interface(log, DEBUG)
557        window.show()
558       
559        sys.exit(app.exec_())
560
Note: See TracBrowser for help on using the repository browser.