def __init__(self, parent=None, noconfig=False): super(Jansen, self).__init__(parent) self.setupUi(self) self.configuration = Configuration(self) # Setup vision tab try: self.vision.close() self.vision.setObjectName("vision") self.vision = QVision(self.tabVision) self.visionLayout.addWidget(self.vision) self.setupVision = True except Exception as ex2: err = ex2 if ex1 is None else ex1 msg = 'Could not import Machine Vision pipeline: {}' logger.warning(msg.format(err)) self.tabWidget.setTabEnabled(2, False) self.setupVision = False # Setup camera self.camera.close() # remove placeholder widget from UI camera = QCamera() self.camera = camera self.screen.camera = camera self.cameraLayout.addWidget(camera) self.configureUi() self.connectSignals() self.doconfig = not noconfig if self.doconfig: self.restoreSettings()
def __init__(self, parent=None, doconfig=True): super(PyFab, self).__init__(parent) self.setupUi(self) self.configuration = Configuration(self) # Camera self.camera.close() # remove placeholder widget from UI camera = QCamera() self.camera = camera self.screen.camera = camera self.cameraLayout.addWidget(camera) # Setup vision tab try: self.vision.close() self.vision.setObjectName("vision") self.vision = QVision(self.tabVision) self.visionLayout.addWidget(self.vision) self.setupVision = True except Exception as ex2: err = ex2 if ex1 is None else ex1 msg = 'Could not import Machine Vision pipeline: {}' logger.warning(msg.format(err)) self.tabWidget.setTabEnabled(2, False) self.setupVision = False # Spatial light modulator self.slm = QSLM(self) # Computation pipeline self.cgh.device = CGH(self, shape=self.slm.shape) self.cgh.device.start() # Trapping pattern is an interactive overlay # that translates user actions into hologram computations self.pattern = QTrappingPattern(parent=self) self.screen.addOverlay(self.pattern) # Trap automated assembly framework self.assembler = TrapAssemble(parent=self) self.mover = TrapMove(parent=self) # Process automation self.tasks = Taskmanager(self) self.configureUi() self.connectSignals() self.doconfig = doconfig if self.doconfig: self.restoreSettings()
def __init__(self, serialProtocol, parent=None): QMainWindow.__init__(self) # setup member variables self.serialProtocol = serialProtocol self.servos = {} self.columns = {} self.updating = False self.listenOnly = False self.timerDataRequest = QTimer(self) self.timerDataRequest.timeout.connect(self.timerDataRequest_timeout) # setup ui self.setupUi(self) self.buttonDataLog.setVisible(False) self.setWindowIcon( QIcon(os.path.join(BASE_PATH, 'res', 'SerialTool.png'))) self.comboProtocolName.addItems( self.serialProtocol.availableProtocolNames) self.restoreGuiSettings() # open configuration file pathToScript = os.path.abspath( os.path.realpath(os.path.dirname(sys.argv[0]))) nameOfScript = os.path.basename(sys.argv[0]) self.configuration = Configuration( os.path.join(pathToScript, '%s.conf' % nameOfScript)) self.converter = DataConverter(bigEndian=False) # restore data from configuration file self.restoreData() # init log view self.logView = LogView(self, self.textLogView) self.spinLogLevel.valueChanged.connect(self.logView.logLevelChanged) self.logView.logLevelChanged.emit(self.spinLogLevel.value( )) # emit signal manually to set initial value # init data plot self.spinDataPlotInterval.valueChanged.connect( self.dataPlotIntervalChanged) self.buttonDataPlotClear.clicked.connect(self.dataPlotClear) self.buttonDataPlotPause.toggled.connect(self.dataPlotTogglePause) self.buttonDataPlotOsciMode.toggled.connect( self.dataPlot.toggleOscilloscopeMode) self.subscribedData = {} self.initTable()
def __init__(self, parent=None, noconfig=False): super(Jansen, self).__init__(parent) uifile = Path('jansenlib').joinpath('JansenWidget.ui') uic.loadUi(uifile, self) self.configuration = Configuration(self) self.setupCamera() self.configureUi() self.connectSignals() self.doconfig = not noconfig if self.doconfig: self.restoreSettings()
def __init__(self, parent=None, doconfig=True): super(PyFab, self).__init__(parent) uifile = Path('pyfablib').joinpath('FabWidget.ui') uic.loadUi(uifile, self) self.configuration = Configuration(self) # Camera self.camera.close() # remove placeholder widget from UI self.camera = QCamera() self.screen.camera = self.camera self.cameraLayout.addWidget(self.camera) # Spatial light modulator self.slm = QSLM(self) # Computation pipeline self.cgh.device = CGH(self, shape=self.slm.shape).start() # Trapping pattern is an interactive overlay # that translates user actions into hologram computations self.pattern = QTrappingPattern(parent=self) self.screen.addOverlay(self.pattern) # Process automation self.tasks = QTaskmanager(self) self.TaskManagerView.setModel(self.tasks) self.TaskManagerView.setSelectionMode(3) self.configureUi() self.connectSignals() self.doconfig = doconfig if self.doconfig: self.restoreSettings()
def __init__(self, serialProtocol, parent=None): QMainWindow.__init__(self) # setup member variables self.serialProtocol = serialProtocol self.servos = {} self.columns = {} self.updating = False self.listenOnly = False self.timerDataRequest = QTimer(self) self.timerDataRequest.timeout.connect(self.timerDataRequest_timeout) # setup ui self.setupUi(self) self.buttonDataLog.setVisible(False) self.setWindowIcon(QIcon(os.path.join(BASE_PATH, 'res', 'SerialTool.png'))) self.comboProtocolName.addItems(self.serialProtocol.availableProtocolNames) self.restoreGuiSettings() # open configuration file pathToScript = os.path.abspath(os.path.realpath(os.path.dirname(sys.argv[0]))) nameOfScript = os.path.basename(sys.argv[0]) self.configuration = Configuration(os.path.join(pathToScript, '%s.conf' % nameOfScript)) self.converter = DataConverter(bigEndian=False) # restore data from configuration file self.restoreData() # init log view self.logView = LogView(self, self.textLogView) self.spinLogLevel.valueChanged.connect(self.logView.logLevelChanged) self.logView.logLevelChanged.emit(self.spinLogLevel.value()) # emit signal manually to set initial value # init data plot self.spinDataPlotInterval.valueChanged.connect(self.dataPlotIntervalChanged) self.buttonDataPlotClear.clicked.connect(self.dataPlotClear) self.buttonDataPlotPause.toggled.connect(self.dataPlotTogglePause) self.buttonDataPlotOsciMode.toggled.connect(self.dataPlot.toggleOscilloscopeMode) self.subscribedData = {} self.initTable()
class PyFab(QMainWindow): def __init__(self, parent=None, doconfig=True): super(PyFab, self).__init__(parent) uifile = Path('pyfablib').joinpath('FabWidget.ui') uic.loadUi(uifile, self) self.configuration = Configuration(self) # Camera self.camera.close() # remove placeholder widget from UI self.camera = QCamera() self.screen.camera = self.camera self.cameraLayout.addWidget(self.camera) # Spatial light modulator self.slm = QSLM(self) # Computation pipeline self.cgh.device = CGH(self, shape=self.slm.shape).start() # Trapping pattern is an interactive overlay # that translates user actions into hologram computations self.pattern = QTrappingPattern(parent=self) self.screen.addOverlay(self.pattern) # Process automation self.tasks = QTaskmanager(self) self.TaskManagerView.setModel(self.tasks) self.TaskManagerView.setSelectionMode(3) self.configureUi() self.connectSignals() self.doconfig = doconfig if self.doconfig: self.restoreSettings() def closeEvent(self, event): self.saveSettings() self.pattern.clearTraps() self.screen.close() self.slm.close() self.cgh.device.stop() self.deleteLater() def configureUi(self): self.filters.screen = self.screen self.histogram.screen = self.screen self.dvr.screen = self.screen self.dvr.source = self.screen.default self.dvr.filename = self.configuration.datadir + 'pyfab.avi' self.TaskPropertiesLayout = QStackedLayout(self.TaskPropertiesView) index = self.tabWidget.indexOf(self.hardware.parent()) self.tabWidget.setTabEnabled(index, self.hardware.has_content()) self.slmView.setRange(xRange=[0, self.slm.width()], yRange=[0, self.slm.height()], padding=0) buildTaskMenu(self) self.adjustSize() def connectSignals(self): # Signals associated with arrival of images from camera newframe = self.screen.source.sigNewFrame # 1. Update histograms from image data newframe.connect(self.histogram.updateHistogram) # 2. CGH computations are coordinated with camera newframe.connect(self.pattern.refresh) # Signals associated with the CGH pipeline # 1. Screen events trigger requests for trap updates self.screen.sigMousePress.connect(self.pattern.mousePress) self.screen.sigMouseRelease.connect(self.pattern.mouseRelease) self.screen.sigMouseMove.connect(self.pattern.mouseMove) self.screen.sigMouseWheel.connect(self.pattern.mouseWheel) # 2. Trap widget reflects changes to trapping pattern self.pattern.sigCompute.connect(self.cgh.device.compute) self.pattern.trapAdded.connect(self.traps.registerTrap) # 3. Project result when calculation is complete self.cgh.device.sigHologramReady.connect(self.slm.setData) self.cgh.device.sigHologramReady.connect(self.slmView.setData) # Signals associated with GUI controls # 1. DVR Source self.bcamera.clicked.connect( lambda: self.setDvrSource(self.screen.default)) self.bfilters.clicked.connect(lambda: self.setDvrSource(self.screen)) # 2. Tab expose events self.tabWidget.currentChanged.connect(self.hardware.expose) self.tabWidget.currentChanged.connect( lambda n: self.slmView.setData(self.cgh.device.phi)) # 3. Task pipeline self.bpausequeue.clicked.connect(self.pauseTasks) self.bclearqueue.clicked.connect(self.stopTasks) self.bpausesel.clicked.connect(self.tasks.toggleSelected) self.bclearsel.clicked.connect(self.tasks.removeSelected) self.bserialize.clicked.connect( lambda: self.tasks.serialize(self.experimentPath.text())) self.bdeserialize.clicked.connect( lambda: self.tasks.registerTask('QExperiment', info=self.experimentPath.text(), loop=self.loop.value())) self.TaskManagerView.clicked.connect(self.tasks.displayProperties) self.TaskManagerView.doubleClicked.connect(self.tasks.toggleCurrent) @pyqtSlot() def setDvrSource(self, source): self.dvr.source = source # # Slots for menu actions # def saveImage(self, qimage, select=False): if qimage is None: return filename = self.configuration.filename(suffix='.png') if select: getname = QFileDialog.getSaveFileName filename, _ = getname(self, 'Save Image', directory=filename, filter='Image files (*.png)') if filename: qimage.save(filename) self.statusBar().showMessage('Saved ' + filename) @pyqtSlot() def savePhoto(self, select=False): qimage = self.screen.imageItem.qimage self.saveImage(qimage, select=select) @pyqtSlot() def savePhotoAs(self): self.savePhoto(select=True) @pyqtSlot() def saveHologram(self, select=False): self.saveImage(self.slm.qimage, select=select) @pyqtSlot() def saveHologramAs(self): self.saveHologram(select=True) @pyqtSlot() def saveSettings(self): if self.doconfig: self.configuration.save(self.camera) self.configuration.save(self.cgh) @pyqtSlot() def restoreSettings(self): if self.doconfig: self.configuration.restore(self.camera) self.configuration.restore(self.cgh) @pyqtSlot() def pauseTasks(self): self.tasks.pauseTasks() msg = 'Tasks paused' if self.tasks.paused else 'Tasks running' self.statusBar().showMessage(msg) @pyqtSlot() def stopTasks(self): self.tasks.clearTasks() self.statusBar().showMessage('Task queue cleared')
from common.Configuration import Configuration from jira import JIRA import importlib FETCHER_CLASS = "fetcher.class" EXECUTOR_CLASS = "executor.class" USER_NAME = "user.name" PASSWD = "password" JIRA_URL = "jira.url" if __name__ == '__main__': if len(sys.argv) == 2: config = Configuration(sys.argv[1]) config.print_conf() user = config.get(USER_NAME)[0] password = config.get(PASSWD)[0] jira_url = config.get(JIRA_URL)[0] jira = JIRA(jira_url, basic_auth=(user, password)) fetcher_module = importlib.import_module('Fetcher.' + config.get(FETCHER_CLASS)[0]) fetcher_class = getattr(fetcher_module, config.get(FETCHER_CLASS)[0]) fetcher = fetcher_class(jira, config) objects = fetcher.fetch() print objects executor_module = importlib.import_module( 'Executor.' + config.get(EXECUTOR_CLASS)[0])
class PyFab(QMainWindow, Ui_PyFab): def __init__(self, parent=None, doconfig=True): super(PyFab, self).__init__(parent) self.setupUi(self) self.configuration = Configuration(self) # Camera self.camera.close() # remove placeholder widget from UI camera = QCamera() self.camera = camera self.screen.camera = camera self.cameraLayout.addWidget(camera) # Setup vision tab try: self.vision.close() self.vision.setObjectName("vision") self.vision = QVision(self.tabVision) self.visionLayout.addWidget(self.vision) self.setupVision = True except Exception as ex2: err = ex2 if ex1 is None else ex1 msg = 'Could not import Machine Vision pipeline: {}' logger.warning(msg.format(err)) self.tabWidget.setTabEnabled(2, False) self.setupVision = False # Spatial light modulator self.slm = QSLM(self) # Computation pipeline self.cgh.device = CGH(self, shape=self.slm.shape) self.cgh.device.start() # Trapping pattern is an interactive overlay # that translates user actions into hologram computations self.pattern = QTrappingPattern(parent=self) self.screen.addOverlay(self.pattern) # Trap automated assembly framework self.assembler = TrapAssemble(parent=self) self.mover = TrapMove(parent=self) # Process automation self.tasks = Taskmanager(self) self.configureUi() self.connectSignals() self.doconfig = doconfig if self.doconfig: self.restoreSettings() def closeEvent(self, event): self.saveSettings() self.pattern.clearTraps() self.screen.close() self.slm.close() self.cgh.device.stop() self.deleteLater() def configureUi(self): self.filters.screen = self.screen self.histogram.screen = self.screen self.dvr.screen = self.screen self.dvr.source = self.screen.default self.dvr.filename = self.configuration.datadir + 'pyfab.avi' if self.setupVision: self.vision.jansen = self index = 3 self.hardware.index = index self.tabWidget.currentChanged.connect(self.hardware.expose) self.tabWidget.setTabEnabled(index, self.hardware.has_content()) self.slmView.setRange(xRange=[0, self.slm.width()], yRange=[0, self.slm.height()], padding=0) self.slmView.setYRange(0, self.slm.height()) buildTaskMenu(self) self.adjustSize() def connectSignals(self): # Signals associated with GUI controls self.bcamera.clicked.connect( lambda: self.setDvrSource(self.screen.default)) self.bfilters.clicked.connect(lambda: self.setDvrSource(self.screen)) # Signals associated with handling images self.screen.source.sigNewFrame.connect(self.histogram.updateHistogram) self.screen.source.sigNewFrame.connect(self.assembler.move) self.screen.source.sigNewFrame.connect(self.mover.move) if self.setupVision: self.screen.sigNewFrame.connect(self.vision.process) # Signals associated with the CGH pipeline # 1. Screen events trigger requests for trap updates self.screen.sigMousePress.connect(self.pattern.mousePress) self.screen.sigMouseRelease.connect(self.pattern.mouseRelease) self.screen.sigMouseMove.connect(self.pattern.mouseMove) self.screen.sigMouseWheel.connect(self.pattern.mouseWheel) # 2. Updates to trapping pattern require hologram calculation self.pattern.sigCompute.connect(self.cgh.device.setTraps) self.pattern.trapAdded.connect(self.traps.registerTrap) # 3. Suppress requests while hologram is being computed self.cgh.device.sigComputing.connect(self.screen.pauseSignals) # 4. Project result when calculation is complete self.cgh.device.sigHologramReady.connect(self.slm.setData) self.cgh.device.sigHologramReady.connect(self.slmView.setData) @pyqtSlot() def setDvrSource(self, source): self.dvr.source = source # # Slots for menu actions # def saveImage(self, qimage, select=False): if qimage is None: return if select: getname = QFileDialog.getSaveFileName directory = self.configuration.datadir filename, _ = getname(self, 'Save Image', directory=directory, filter='Image files (*.png)') else: filename = self.configuration.filename(suffix='.png') if filename: qimage.save(filename) self.statusBar().showMessage('Saved ' + filename) @pyqtSlot() def savePhoto(self, select=False): qimage = self.screen.imageItem.qimage.mirrored(vertical=True) self.saveImage(qimage, select=select) @pyqtSlot() def savePhotoAs(self): self.savePhoto(select=True) @pyqtSlot() def saveHologram(self, select=False): self.saveImage(self.slm.qimage, select=select) @pyqtSlot() def saveHologramAs(self): self.saveHologram(select=True) @pyqtSlot() def saveSettings(self): if self.doconfig: self.configuration.save(self.camera) self.configuration.save(self.cgh) if self.setupVision: self.configuration.save(self.vision) @pyqtSlot() def restoreSettings(self): if self.doconfig: self.configuration.restore(self.camera) self.configuration.restore(self.cgh) if self.setupVision: self.configuration.restore(self.vision) @pyqtSlot() def pauseTasks(self): self.tasks.pauseTasks() msg = 'Tasks paused' if self.tasks.paused() else 'Tasks running' self.statusBar().showMessage(msg) @pyqtSlot() def stopTasks(self): self.tasks.clearTasks() self.statusBar().showMessage('Task queue cleared')
class MainWindow(QMainWindow, MainWindowClass): serialConnectionOpen = Signal(str, int) serialConnectionClose = Signal() serialConnectionStartListening = Signal() serialConnectionPing = Signal(list) serialConnectionScan = Signal() serialConnectionScanSlow = Signal() serialConnectionReadAllData = Signal(list) serialConnectionReadData = Signal(list, int, int) serialConnectionWriteData = Signal(list, int, list) serialConnectionSendData = Signal(list) serialConnectionSendCustomPacket = Signal(int, str, list) def __init__(self, serialProtocol, parent=None): QMainWindow.__init__(self) # setup member variables self.serialProtocol = serialProtocol self.servos = {} self.columns = {} self.updating = False self.listenOnly = False self.timerDataRequest = QTimer(self) self.timerDataRequest.timeout.connect(self.timerDataRequest_timeout) # setup ui self.setupUi(self) self.buttonDataLog.setVisible(False) self.setWindowIcon(QIcon(os.path.join(BASE_PATH, 'res', 'SerialTool.png'))) self.comboProtocolName.addItems(self.serialProtocol.availableProtocolNames) self.restoreGuiSettings() # open configuration file pathToScript = os.path.abspath(os.path.realpath(os.path.dirname(sys.argv[0]))) nameOfScript = os.path.basename(sys.argv[0]) self.configuration = Configuration(os.path.join(pathToScript, '%s.conf' % nameOfScript)) self.converter = DataConverter(bigEndian=False) # restore data from configuration file self.restoreData() # init log view self.logView = LogView(self, self.textLogView) self.spinLogLevel.valueChanged.connect(self.logView.logLevelChanged) self.logView.logLevelChanged.emit(self.spinLogLevel.value()) # emit signal manually to set initial value # init data plot self.spinDataPlotInterval.valueChanged.connect(self.dataPlotIntervalChanged) self.buttonDataPlotClear.clicked.connect(self.dataPlotClear) self.buttonDataPlotPause.toggled.connect(self.dataPlotTogglePause) self.buttonDataPlotOsciMode.toggled.connect(self.dataPlot.toggleOscilloscopeMode) self.subscribedData = {} self.initTable() def initTable(self): # stop the update timer self.timerDataRequest.stop() # init servo memory data table self.tableServoData.clear() self.tableServoData.setColumnCount(1) self.tableServoData.setHorizontalHeaderItem(0, QTableWidgetItem('Parameter')) self.tableServoData.setRowCount(len(self.serialProtocol.memoryInfo['fieldNames'])) rowNumber = 0 for fieldName in self.serialProtocol.memoryInfo['fieldNames']: fieldInfo = self.serialProtocol.memoryInfo[fieldName] nameItem = QTableWidgetItem(fieldInfo['name']) if fieldInfo['writable']: nameItem.setFlags(Qt.ItemIsEnabled | Qt.ItemIsSelectable) else: nameItem.setFlags(Qt.ItemFlag()) self.tableServoData.setItem(rowNumber, 0, nameItem) self.tableServoData.resizeRowToContents(rowNumber) self.tableServoData.setRowHeight(rowNumber, self.tableServoData.rowHeight(rowNumber) - 7) rowNumber += 1 self.tableServoData.resizeColumnToContents(0) # restart the update timer self.timerDataRequest.start(20) def closeEvent(self, event): self.saveGuiSettings() self.storeData() def storeData(self): # save baudrate combo baudrateList = [] for i in range(self.comboSerialBaudrate.count()): baudrateList.append(int(self.comboSerialBaudrate.itemText(i))) baudrate = int(self.comboSerialBaudrate.currentText()) baudrateList.sort() self.configuration.set('baudrateList', baudrateList) self.configuration.set('baudrate', baudrate) # save serial port combo portNameList = [] for i in range(self.comboSerialPort.count()): portNameList.append(str(self.comboSerialPort.itemText(i))) portName = str(self.comboSerialPort.currentText()) self.configuration.set('portNameList_%s' % os.name, portNameList) self.configuration.set('portName_%s' % os.name, portName) protocolName = str(self.comboProtocolName.currentText()) self.configuration.set('protocolName', protocolName) def restoreData(self): # init baudrate combo baudrateList = self.configuration.get('baudrateList', [57600, 500000, 1000000]) baudrate = self.configuration.get('baudrate', baudrateList[0]) if not baudrate in baudrateList: baudrateList.append(baudrate) baudrateList.sort() currentIndex = baudrateList.index(baudrate) self.comboSerialBaudrate.addItems(map(str, baudrateList)) self.comboSerialBaudrate.setCurrentIndex(currentIndex) # init serial port combo portNameList = self.configuration.get('portNameList_%s' % os.name, ['/dev/ttyUSB0']) if os.name == 'posix': portNameList = list(set(portNameList + glob.glob('/dev/ttyUSB*'))) portName = self.configuration.get('portName_%s' % os.name, portNameList[0]) portNameList.sort() self.comboSerialPort.addItems(portNameList) if portName in portNameList: self.comboSerialPort.setCurrentIndex(portNameList.index(portName)) elif self.comboSerialPort.count > 0: self.comboSerialPort.setCurrentIndex(0) protocolName = self.configuration.get('protocolName', 'RobotisServo') self.comboProtocolName.setCurrentIndex(self.comboProtocolName.findText(protocolName)) def saveGuiSettings(self): settings = QSettings('sim.informatik.tu-darmstadt.de', 'Servo Tool') settings.beginGroup('MainWindow') settings.setValue('state', QVariant(self.saveState())) settings.setValue('size', QVariant(self.size())) settings.setValue('pos', QVariant(self.pos())) settings.setValue('splitter', QVariant(self.splitter.saveState())) settings.setValue('splitter_2', QVariant(self.splitter_2.saveState())) settings.setValue('logLevel', QVariant(self.spinLogLevel.value())) settings.endGroup() def restoreGuiSettings(self): settings = QSettings('sim.informatik.tu-darmstadt.de', 'Servo Tool') settings.beginGroup('MainWindow') self.restoreState(settings.value('state', QVariant(QByteArray())).toByteArray()) self.resize(settings.value('size', QVariant(QSize(800, 600))).toSize()) self.move(settings.value('pos', QVariant(QPoint(200, 200))).toPoint()) self.splitter.restoreState(settings.value('splitter', QVariant(QByteArray())).toByteArray()) self.splitter_2.restoreState(settings.value('splitter_2', QVariant(QByteArray())).toByteArray()) self.spinLogLevel.setValue(settings.value('logLevel', QVariant(3)).toInt()[0]) settings.endGroup() def log(self, level, message): self.logView.logMessage.emit(level, message) def packetSent(self, packetBytes): # clear received data field, so unanswered packets don't show the last received packet self.textDataReceived.clear() formatString = '%02x ' * len(packetBytes) packetString = formatString % tuple(packetBytes) self.textDataSent.clear() self.textDataSent.appendPlainText(packetString) def packetReceived(self, packetBytes): formatString = '%02x ' * len(packetBytes) packetString = formatString % tuple(packetBytes) self.textDataReceived.clear() self.textDataReceived.appendPlainText(packetString) def servoChangedId(self, oldServoId, newServoId): self.comboServoId.setItemText(self.comboServoId.findText('%d' % oldServoId), '%d' % newServoId) columnNumber = self.servos[oldServoId]['columnNumber'] self.tableServoData.setHorizontalHeaderItem(columnNumber, QTableWidgetItem('Id %d' % newServoId)) self.tableServoData.resizeColumnToContents(columnNumber) self.servos[newServoId] = self.servos[oldServoId] self.servos[newServoId]['id'] = newServoId del self.servos[oldServoId] def servoDelete(self, servoId): self.comboServoId.removeItem(self.comboServoId.findText('%d' % servoId)) columnNumber = self.servos[servoId]['columnNumber'] # remove table column self.tableServoData.removeColumn(columnNumber) # remove servo mapping del self.servos[servoId] # correct other servo->column->servo mappings for servo in self.servos.values(): if servo['columnNumber'] > columnNumber: del self.columns[servo['columnNumber']] servo['columnNumber'] -= 1 self.columns[servo['columnNumber']] = servo def servoAdd(self, servoId): if self.servos.has_key(servoId): return self.comboServoId.addItem('%d' % servoId) columnNumber = self.tableServoData.columnCount() self.tableServoData.setColumnCount(columnNumber + 1) self.tableServoData.setHorizontalHeaderItem(columnNumber, QTableWidgetItem('Id %d' % servoId)) self.tableServoData.resizeColumnToContents(columnNumber) self.servos[servoId] = {'id' : servoId, 'columnNumber': columnNumber} self.columns[columnNumber] = self.servos[servoId] self.labelNumServosFound.setText('%d found' % len(self.servos)) def servoDataUpdate(self, servoId, addressOffset, servoData): if not self.servos.has_key(servoId): self.servoAdd(servoId) columnNumber = self.servos[servoId]['columnNumber'] self.updating = True servoDataString = ('%c' * len(servoData)) % tuple(chr(c) for c in servoData) index = 0 while index < len(servoDataString): fieldInfo = self.serialProtocol.memoryInfo[addressOffset + index] if fieldInfo['numElements'] != 1: self.log(0, 'ERROR: MainWindow.servoDataUpdate(): numElements != 1 -> Arrays are not supported, yet...') value = self.converter.fromString(servoDataString[index:], fieldInfo['type']) index += fieldInfo['size'] # check if the item is being plotted subscribeId = '[%d].%s' % (servoId, fieldInfo['name']) if self.subscribedData.has_key(subscribeId): self.dataPlot.updateValue(subscribeId, float(value)) # check for existing item, or create a new one dataItem = self.tableServoData.item(fieldInfo['index'], columnNumber) if not dataItem: dataItem = QTableWidgetItem() if fieldInfo['writable']: dataItem.setFlags(Qt.ItemIsEnabled | Qt.ItemIsEditable | Qt.ItemIsSelectable) else: dataItem.setFlags(Qt.ItemFlag()) self.tableServoData.setItem(fieldInfo['index'], columnNumber, dataItem) if type(value) == float: valueString = ('%.7f' % value).rstrip('0') else: valueString = str(value) dataItem.setText(valueString) # update item text dataItem.setToolTip(fieldInfo['makeToolTip'](value)) # update item tool tip self.tableServoData.resizeColumnToContents(columnNumber) self.updating = False def serialConnectionError(self): if self.buttonSerialConnect.isChecked(): self.buttonSerialConnect.click() @Slot(str) def on_comboProtocolName_currentIndexChanged(self, text): self.serialProtocol.setProtocol(str(text)) self.comboCustomCommand.clear() self.comboCustomCommand.addItems(self.serialProtocol.instructionName.values()) servoIdList = self.servos.keys() self.servos = {} self.columns = {} self.initTable() for servoId in servoIdList: self.servoAdd(servoId) def enableButtons(self, enable): self.buttonServoScan.setEnabled(enable) self.buttonServoReadAll.setEnabled(enable) self.buttonServoRead.setEnabled(enable) self.buttonServoPing.setEnabled(enable) self.buttonCustomPacketSend.setEnabled(enable) @Slot(bool) def on_buttonSerialConnect_toggled(self, checked): self.comboSerialPort.setEnabled(not checked) self.comboSerialBaudrate.setEnabled(not checked) self.checkListenOnly.setEnabled(not checked) if checked: self.listenOnly = self.checkListenOnly.isChecked() self.enableButtons(not self.listenOnly) portName = str(self.comboSerialPort.currentText()).strip() if self.comboSerialPort.findText(portName) < 0: self.comboSerialPort.addItem(portName) self.serialConnectionOpen.emit(portName, int(self.comboSerialBaudrate.currentText())) if self.listenOnly: self.serialConnectionStartListening.emit() else: self.enableButtons(True) self.listenOnly = False self.dataPlotClear() self.servos = {} self.columns = {} self.tableServoData.setColumnCount(1) self.serialConnectionClose.emit() @Slot() def on_buttonServoScan_clicked(self): if not self.buttonSerialConnect.isChecked(): self.buttonSerialConnect.click() self.servos = {} self.columns = {} self.tableServoData.setColumnCount(1) self.serialConnectionScan.emit() @Slot() def on_buttonServoScanSlow_clicked(self): if not self.buttonSerialConnect.isChecked(): self.buttonSerialConnect.click() self.servos = {} self.columns = {} self.tableServoData.setColumnCount(1) self.serialConnectionScanSlow.emit() @Slot() def on_buttonServoReadAll_clicked(self): if not self.servos: self.on_buttonServoScan_clicked() self.serialConnectionReadAllData.emit(self.servos.keys()) def getServoIdFrom_comboServoId(self): servoIdString = str(self.comboServoId.currentText()).strip() if len(servoIdString) == 0: self.log(0, 'Please enter a servo id.') return None try: servoId = int(servoIdString) except Exception, e: self.log(0, 'Error: %s' % e) return None return servoId
class Jansen(QMainWindow, Ui_Jansen): def __init__(self, parent=None, noconfig=False): super(Jansen, self).__init__(parent) self.setupUi(self) self.configuration = Configuration(self) # Setup vision tab try: self.vision.close() self.vision.setObjectName("vision") self.vision = QVision(self.tabVision) self.visionLayout.addWidget(self.vision) self.setupVision = True except Exception as ex2: err = ex2 if ex1 is None else ex1 msg = 'Could not import Machine Vision pipeline: {}' logger.warning(msg.format(err)) self.tabWidget.setTabEnabled(2, False) self.setupVision = False # Setup camera self.camera.close() # remove placeholder widget from UI camera = QCamera() self.camera = camera self.screen.camera = camera self.cameraLayout.addWidget(camera) self.configureUi() self.connectSignals() self.doconfig = not noconfig if self.doconfig: self.restoreSettings() def closeEvent(self, event): self.saveSettings() self.screen.close() self.deleteLater() def configureUi(self): self.filters.screen = self.screen self.histogram.screen = self.screen self.dvr.screen = self.screen self.dvr.source = self.screen.default self.dvr.filename = self.configuration.datadir + 'jansen.avi' if self.setupVision: self.vision.jansen = self self.adjustSize() def connectSignals(self): self.bcamera.clicked.connect( lambda: self.setDvrSource(self.screen.default)) self.bfilters.clicked.connect( lambda: self.setDvrSource(self.screen)) self.actionSavePhoto.triggered.connect(self.savePhoto) self.actionSavePhotoAs.triggered.connect( lambda: self.savePhoto(True)) # Signals associated with handling images self.screen.source.sigNewFrame.connect(self.histogram.updateHistogram) if self.setupVision: self.screen.sigNewFrame.connect(self.vision.process) @pyqtSlot() def setDvrSource(self, source): self.dvr.source = source # # Slots for menu actions # def saveImage(self, qimage, select=False): if qimage is None: return if select: getname = QFileDialog.getSaveFileName filename, _ = getname(self, 'Save Image', directory=filename, filter='Image files (*.png)') else: filename = self.configuration.filename(suffix='.png') if filename: qimage.save(filename) self.statusBar().showMessage('Saved ' + filename) @pyqtSlot() def savePhoto(self, select=False): qimage = self.screen.imageItem.qimage.mirrored(vertical=True) self.saveImage(qimage, select=select) @pyqtSlot() def savePhotoAs(self): self.savePhoto(select=True) @pyqtSlot() def saveSettings(self): if self.doconfig: self.configuration.save(self.camera) if self.setupVision: self.configuration.save(self.vision) @pyqtSlot() def restoreSettings(self): if self.doconfig: self.configuration.restore(self.camera) if self.setupVision: self.configuration.restore(self.vision)
class MainWindow(QMainWindow, MainWindowClass): serialConnectionOpen = Signal(str, int) serialConnectionClose = Signal() serialConnectionStartListening = Signal() serialConnectionPing = Signal(list) serialConnectionScan = Signal() serialConnectionScanSlow = Signal() serialConnectionReadAllData = Signal(list) serialConnectionReadData = Signal(list, int, int) serialConnectionWriteData = Signal(list, int, list) serialConnectionSendData = Signal(list) serialConnectionSendCustomPacket = Signal(int, str, list) def __init__(self, serialProtocol, parent=None): QMainWindow.__init__(self) # setup member variables self.serialProtocol = serialProtocol self.servos = {} self.columns = {} self.updating = False self.listenOnly = False self.timerDataRequest = QTimer(self) self.timerDataRequest.timeout.connect(self.timerDataRequest_timeout) # setup ui self.setupUi(self) self.buttonDataLog.setVisible(False) self.setWindowIcon( QIcon(os.path.join(BASE_PATH, 'res', 'SerialTool.png'))) self.comboProtocolName.addItems( self.serialProtocol.availableProtocolNames) self.restoreGuiSettings() # open configuration file pathToScript = os.path.abspath( os.path.realpath(os.path.dirname(sys.argv[0]))) nameOfScript = os.path.basename(sys.argv[0]) self.configuration = Configuration( os.path.join(pathToScript, '%s.conf' % nameOfScript)) self.converter = DataConverter(bigEndian=False) # restore data from configuration file self.restoreData() # init log view self.logView = LogView(self, self.textLogView) self.spinLogLevel.valueChanged.connect(self.logView.logLevelChanged) self.logView.logLevelChanged.emit(self.spinLogLevel.value( )) # emit signal manually to set initial value # init data plot self.spinDataPlotInterval.valueChanged.connect( self.dataPlotIntervalChanged) self.buttonDataPlotClear.clicked.connect(self.dataPlotClear) self.buttonDataPlotPause.toggled.connect(self.dataPlotTogglePause) self.buttonDataPlotOsciMode.toggled.connect( self.dataPlot.toggleOscilloscopeMode) self.subscribedData = {} self.initTable() def initTable(self): # stop the update timer self.timerDataRequest.stop() # init servo memory data table self.tableServoData.clear() self.tableServoData.setColumnCount(1) self.tableServoData.setHorizontalHeaderItem( 0, QTableWidgetItem('Parameter')) self.tableServoData.setRowCount( len(self.serialProtocol.memoryInfo['fieldNames'])) rowNumber = 0 for fieldName in self.serialProtocol.memoryInfo['fieldNames']: fieldInfo = self.serialProtocol.memoryInfo[fieldName] nameItem = QTableWidgetItem(fieldInfo['name']) if fieldInfo['writable']: nameItem.setFlags(Qt.ItemIsEnabled | Qt.ItemIsSelectable) else: nameItem.setFlags(Qt.ItemFlag()) self.tableServoData.setItem(rowNumber, 0, nameItem) self.tableServoData.resizeRowToContents(rowNumber) self.tableServoData.setRowHeight( rowNumber, self.tableServoData.rowHeight(rowNumber) - 7) rowNumber += 1 self.tableServoData.resizeColumnToContents(0) # restart the update timer self.timerDataRequest.start(20) def closeEvent(self, event): self.saveGuiSettings() self.storeData() def storeData(self): # save baudrate combo baudrateList = [] for i in range(self.comboSerialBaudrate.count()): baudrateList.append(int(self.comboSerialBaudrate.itemText(i))) baudrate = int(self.comboSerialBaudrate.currentText()) baudrateList.sort() self.configuration.set('baudrateList', baudrateList) self.configuration.set('baudrate', baudrate) # save serial port combo portNameList = [] for i in range(self.comboSerialPort.count()): portNameList.append(str(self.comboSerialPort.itemText(i))) portName = str(self.comboSerialPort.currentText()) self.configuration.set('portNameList_%s' % os.name, portNameList) self.configuration.set('portName_%s' % os.name, portName) protocolName = str(self.comboProtocolName.currentText()) self.configuration.set('protocolName', protocolName) def restoreData(self): # init baudrate combo baudrateList = self.configuration.get('baudrateList', [57600, 500000, 1000000]) baudrate = self.configuration.get('baudrate', baudrateList[0]) if not baudrate in baudrateList: baudrateList.append(baudrate) baudrateList.sort() currentIndex = baudrateList.index(baudrate) self.comboSerialBaudrate.addItems(map(str, baudrateList)) self.comboSerialBaudrate.setCurrentIndex(currentIndex) # init serial port combo portNameList = self.configuration.get('portNameList_%s' % os.name, ['/dev/ttyUSB0']) if os.name == 'posix': portNameList = list(set(portNameList + glob.glob('/dev/ttyUSB*'))) portName = self.configuration.get('portName_%s' % os.name, portNameList[0]) portNameList.sort() self.comboSerialPort.addItems(portNameList) if portName in portNameList: self.comboSerialPort.setCurrentIndex(portNameList.index(portName)) elif self.comboSerialPort.count > 0: self.comboSerialPort.setCurrentIndex(0) protocolName = self.configuration.get('protocolName', 'RobotisServo') self.comboProtocolName.setCurrentIndex( self.comboProtocolName.findText(protocolName)) def saveGuiSettings(self): settings = QSettings('sim.informatik.tu-darmstadt.de', 'Servo Tool') settings.beginGroup('MainWindow') settings.setValue('state', QVariant(self.saveState())) settings.setValue('size', QVariant(self.size())) settings.setValue('pos', QVariant(self.pos())) settings.setValue('splitter', QVariant(self.splitter.saveState())) settings.setValue('splitter_2', QVariant(self.splitter_2.saveState())) settings.setValue('logLevel', QVariant(self.spinLogLevel.value())) settings.endGroup() def restoreGuiSettings(self): settings = QSettings('sim.informatik.tu-darmstadt.de', 'Servo Tool') settings.beginGroup('MainWindow') self.restoreState( settings.value('state', QVariant(QByteArray())).toByteArray()) self.resize(settings.value('size', QVariant(QSize(800, 600))).toSize()) self.move(settings.value('pos', QVariant(QPoint(200, 200))).toPoint()) self.splitter.restoreState( settings.value('splitter', QVariant(QByteArray())).toByteArray()) self.splitter_2.restoreState( settings.value('splitter_2', QVariant(QByteArray())).toByteArray()) self.spinLogLevel.setValue( settings.value('logLevel', QVariant(3)).toInt()[0]) settings.endGroup() def log(self, level, message): self.logView.logMessage.emit(level, message) def packetSent(self, packetBytes): # clear received data field, so unanswered packets don't show the last received packet self.textDataReceived.clear() formatString = '%02x ' * len(packetBytes) packetString = formatString % tuple(packetBytes) self.textDataSent.clear() self.textDataSent.appendPlainText(packetString) def packetReceived(self, packetBytes): formatString = '%02x ' * len(packetBytes) packetString = formatString % tuple(packetBytes) self.textDataReceived.clear() self.textDataReceived.appendPlainText(packetString) def servoChangedId(self, oldServoId, newServoId): self.comboServoId.setItemText( self.comboServoId.findText('%d' % oldServoId), '%d' % newServoId) columnNumber = self.servos[oldServoId]['columnNumber'] self.tableServoData.setHorizontalHeaderItem( columnNumber, QTableWidgetItem('Id %d' % newServoId)) self.tableServoData.resizeColumnToContents(columnNumber) self.servos[newServoId] = self.servos[oldServoId] self.servos[newServoId]['id'] = newServoId del self.servos[oldServoId] def servoDelete(self, servoId): self.comboServoId.removeItem(self.comboServoId.findText('%d' % servoId)) columnNumber = self.servos[servoId]['columnNumber'] # remove table column self.tableServoData.removeColumn(columnNumber) # remove servo mapping del self.servos[servoId] # correct other servo->column->servo mappings for servo in self.servos.values(): if servo['columnNumber'] > columnNumber: del self.columns[servo['columnNumber']] servo['columnNumber'] -= 1 self.columns[servo['columnNumber']] = servo def servoAdd(self, servoId): if self.servos.has_key(servoId): return self.comboServoId.addItem('%d' % servoId) columnNumber = self.tableServoData.columnCount() self.tableServoData.setColumnCount(columnNumber + 1) self.tableServoData.setHorizontalHeaderItem( columnNumber, QTableWidgetItem('Id %d' % servoId)) self.tableServoData.resizeColumnToContents(columnNumber) self.servos[servoId] = {'id': servoId, 'columnNumber': columnNumber} self.columns[columnNumber] = self.servos[servoId] self.labelNumServosFound.setText('%d found' % len(self.servos)) def servoDataUpdate(self, servoId, addressOffset, servoData): if not self.servos.has_key(servoId): self.servoAdd(servoId) columnNumber = self.servos[servoId]['columnNumber'] self.updating = True servoDataString = ('%c' * len(servoData)) % tuple( chr(c) for c in servoData) index = 0 while index < len(servoDataString): fieldInfo = self.serialProtocol.memoryInfo[addressOffset + index] if fieldInfo['numElements'] != 1: self.log( 0, 'ERROR: MainWindow.servoDataUpdate(): numElements != 1 -> Arrays are not supported, yet...' ) value = self.converter.fromString(servoDataString[index:], fieldInfo['type']) index += fieldInfo['size'] # check if the item is being plotted subscribeId = '[%d].%s' % (servoId, fieldInfo['name']) if self.subscribedData.has_key(subscribeId): self.dataPlot.updateValue(subscribeId, float(value)) # check for existing item, or create a new one dataItem = self.tableServoData.item(fieldInfo['index'], columnNumber) if not dataItem: dataItem = QTableWidgetItem() if fieldInfo['writable']: dataItem.setFlags(Qt.ItemIsEnabled | Qt.ItemIsEditable | Qt.ItemIsSelectable) else: dataItem.setFlags(Qt.ItemFlag()) self.tableServoData.setItem(fieldInfo['index'], columnNumber, dataItem) if type(value) == float: valueString = ('%.7f' % value).rstrip('0') else: valueString = str(value) dataItem.setText(valueString) # update item text dataItem.setToolTip( fieldInfo['makeToolTip'](value)) # update item tool tip self.tableServoData.resizeColumnToContents(columnNumber) self.updating = False def serialConnectionError(self): if self.buttonSerialConnect.isChecked(): self.buttonSerialConnect.click() @Slot(str) def on_comboProtocolName_currentIndexChanged(self, text): self.serialProtocol.setProtocol(str(text)) self.comboCustomCommand.clear() self.comboCustomCommand.addItems( self.serialProtocol.instructionName.values()) servoIdList = self.servos.keys() self.servos = {} self.columns = {} self.initTable() for servoId in servoIdList: self.servoAdd(servoId) def enableButtons(self, enable): self.buttonServoScan.setEnabled(enable) self.buttonServoReadAll.setEnabled(enable) self.buttonServoRead.setEnabled(enable) self.buttonServoPing.setEnabled(enable) self.buttonCustomPacketSend.setEnabled(enable) @Slot(bool) def on_buttonSerialConnect_toggled(self, checked): self.comboSerialPort.setEnabled(not checked) self.comboSerialBaudrate.setEnabled(not checked) self.checkListenOnly.setEnabled(not checked) if checked: self.listenOnly = self.checkListenOnly.isChecked() self.enableButtons(not self.listenOnly) portName = str(self.comboSerialPort.currentText()).strip() if self.comboSerialPort.findText(portName) < 0: self.comboSerialPort.addItem(portName) self.serialConnectionOpen.emit( portName, int(self.comboSerialBaudrate.currentText())) if self.listenOnly: self.serialConnectionStartListening.emit() else: self.enableButtons(True) self.listenOnly = False self.dataPlotClear() self.servos = {} self.columns = {} self.tableServoData.setColumnCount(1) self.serialConnectionClose.emit() @Slot() def on_buttonServoScan_clicked(self): if not self.buttonSerialConnect.isChecked(): self.buttonSerialConnect.click() self.servos = {} self.columns = {} self.tableServoData.setColumnCount(1) self.serialConnectionScan.emit() @Slot() def on_buttonServoScanSlow_clicked(self): if not self.buttonSerialConnect.isChecked(): self.buttonSerialConnect.click() self.servos = {} self.columns = {} self.tableServoData.setColumnCount(1) self.serialConnectionScanSlow.emit() @Slot() def on_buttonServoReadAll_clicked(self): if not self.servos: self.on_buttonServoScan_clicked() self.serialConnectionReadAllData.emit(self.servos.keys()) def getServoIdFrom_comboServoId(self): servoIdString = str(self.comboServoId.currentText()).strip() if len(servoIdString) == 0: self.log(0, 'Please enter a servo id.') return None try: servoId = int(servoIdString) except Exception, e: self.log(0, 'Error: %s' % e) return None return servoId
class Jansen(QMainWindow): def __init__(self, parent=None, noconfig=False): super(Jansen, self).__init__(parent) uifile = Path('jansenlib').joinpath('JansenWidget.ui') uic.loadUi(uifile, self) self.configuration = Configuration(self) self.setupCamera() self.configureUi() self.connectSignals() self.doconfig = not noconfig if self.doconfig: self.restoreSettings() def closeEvent(self, event): self.saveSettings() self.screen.close() self.deleteLater() def setupCamera(self): self.camera.close() # remove placeholder widget from UI camera = QCamera() self.camera = camera self.screen.camera = camera self.cameraLayout.addWidget(camera) def configureUi(self): self.filters.screen = self.screen self.histogram.screen = self.screen self.dvr.screen = self.screen self.dvr.source = self.screen.default self.dvr.filename = self.configuration.datadir + 'jansen.avi' self.adjustSize() def connectSignals(self): self.bcamera.clicked.connect( lambda: self.setDvrSource(self.screen.default)) self.bfilters.clicked.connect(lambda: self.setDvrSource(self.screen)) self.actionSavePhoto.triggered.connect(self.savePhoto) self.actionSavePhotoAs.triggered.connect(lambda: self.savePhoto(True)) # Signals associated with handling images self.screen.source.sigNewFrame.connect(self.histogram.updateHistogram) @pyqtSlot() def setDvrSource(self, source): self.dvr.source = source # # Slots for menu actions # def saveImage(self, qimage, select=False): if qimage is None: return filename = self.configuration.filename(suffix='.png') if select: getname = QFileDialog.getSaveFileName filename, _ = getname(self, 'Save Image', directory=filename, filter='Image files (*.png)') if filename: qimage.save(filename) self.statusBar().showMessage('Saved ' + filename) @pyqtSlot() def savePhoto(self, select=False): qimage = self.screen.imageItem.qimage.mirrored(vertical=True) self.saveImage(qimage, select=select) @pyqtSlot() def savePhotoAs(self): self.savePhoto(select=True) @pyqtSlot() def saveSettings(self): if self.doconfig: self.configuration.save(self.camera) @pyqtSlot() def restoreSettings(self): if self.doconfig: self.configuration.restore(self.camera)