#!/usr/bin/env python # # this script demonstrates some basic features of taurus programs # - the application is started as a mainWindow # - a motor can be moved from a button or a slider # - a sequence (move motor up and down) is executed while the GUI stays active # - a dscan sequence is executed while the GUI stays active # - motor moves can be stopped # - the dscan macro can be aborted # - a QTimer() is included, needs to be uncommented # import sys, time, os from taurus.external.qt import Qt from taurus.external.qt import QtCore from taurus.external.qt import QtGui from taurus.qt.qtgui.application import TaurusApplication from taurus.qt.qtgui.display import TaurusLabel from taurus.core.taurushelper import changeDefaultPollingPeriod import HasyUtils import PyTango SLIDER_RESOLUTION = 500 POSITION_WIDTH = 120 TIMEOUT_REFRESH = 500 class moveMotor( Qt.QMainWindow): def __init__( self, dev, parent = None): super( moveMotor, self).__init__( parent) self.dev = dev self.setWindowTitle( "Move %s" % dev[ 'name']) self.move( 10, 750) self.prepareWidgets() self.sliderPosition = None self.motor = dev[ 'proxy'] self.updateWidgets() #self.updateTimer.start( TIMEOUT_REFRESH) def prepareWidgets( self): w = Qt.QWidget() self.layout_v = Qt.QVBoxLayout() w.setLayout( self.layout_v) self.setCentralWidget( w) # # the alias line # hBox = Qt.QHBoxLayout() self.w_alias = Qt.QPushButton() hBox.addWidget( self.w_alias) hBox.addStretch() self.layout_v.addLayout( hBox) # # position, moveTo # hBox = Qt.QHBoxLayout() hBox.addWidget( Qt.QLabel( "Position")) self.w_motorPosition = TaurusLabel() self.w_motorPosition.setFixedWidth( POSITION_WIDTH) hBox.addWidget( self.w_motorPosition) hBox.addStretch() hBox.addWidget( Qt.QLabel( "Target")) hBox.addStretch() self.moveButton = Qt.QPushButton(self.tr("&Move")) self.moveButton.setShortcut( "Alt+m") self.moveButton.setToolTip( "Start move with backlash") hBox.addWidget( self.moveButton) self.moveButton.clicked.connect( self.moveTo) self.moveToLine = Qt.QLineEdit() self.moveToLine.setFixedWidth( POSITION_WIDTH) self.moveToLine.setAlignment( QtCore.Qt.AlignRight) hBox.addWidget( self.moveToLine) self.layout_v.addLayout( hBox) # # the slider # frame = Qt.QFrame() frame.setFrameShape( Qt.QFrame.Box) self.layout_v.addWidget( frame) self.layout_frame_v = Qt.QVBoxLayout() frame.setLayout( self.layout_frame_v) self.w_slider = Qt.QSlider() # # install an event filter for the slider, basically to catch # arrow-up and arrow-down events. Up/Down are not caught, if # the filter is applied to self. # self.w_slider.installEventFilter( self) self.w_slider.setOrientation( 1) # 1 horizontal, 2 vertical self.w_slider.setToolTip( "Moving the slider moves the motor, upon mouse-release.") self.layout_frame_v.addWidget( self.w_slider) self.w_slider.sliderReleased.connect( self.cb_sliderReleased) self.w_slider.valueChanged.connect( self.cb_sliderValueChanged) # # the slider: min, sliderPosition, max # hBox = Qt.QHBoxLayout() self.w_motorLimitMin = TaurusLabel() self.w_motorLimitMin.setMinimumWidth( POSITION_WIDTH) hBox.addWidget( self.w_motorLimitMin) hBox.addStretch() self.w_sliderPosition = Qt.QLabel() hBox.addWidget( self.w_sliderPosition) hBox.addStretch() self.w_motorLimitMax = TaurusLabel() self.w_motorLimitMax.setMinimumWidth( POSITION_WIDTH) hBox.addWidget( self.w_motorLimitMax) self.layout_frame_v.addLayout( hBox) # stop self.flagStopped = False self.w_stop = Qt.QPushButton(self.tr("&Stop")) self.w_stop.setFixedWidth( 70) self.w_stop.clicked.connect( self.cb_stopMove) self.w_stop.setShortcut( "Alt+s") hBox.addWidget( self.w_stop) # # Menu Bar # self.menuBar = Qt.QMenuBar() self.setMenuBar( self.menuBar) self.prepareMenuBar() # # Status Bar # self.statusBar = Qt.QStatusBar() self.setStatusBar( self.statusBar) # # create the log widget, if necessary # self.logWidget = Qt.QTextEdit() self.logWidget.setMaximumHeight( 150) self.logWidget.setReadOnly( 1) self.layout_v.addWidget( self.logWidget) self.w_stop = Qt.QPushButton(self.tr("Stop")) self.w_stop.setToolTip( "Stop move") self.statusBar.addPermanentWidget( self.w_stop) # 'permanent' to shift it right self.w_stop.clicked.connect( self.cb_stopMove) self.w_abort = Qt.QPushButton(self.tr("Abort")) self.w_abort.setToolTip( "Abort macro") self.statusBar.addPermanentWidget( self.w_abort) # self.w_abort.clicked.connect( self.cb_abort) self.w_clear = Qt.QPushButton(self.tr("Clear")) self.w_clear.setToolTip( "Clear log widget") self.statusBar.addPermanentWidget( self.w_clear) self.w_clear.clicked.connect( self.logWidget.clear) self.exit = Qt.QPushButton(self.tr("&Exit")) self.statusBar.addPermanentWidget( self.exit) self.exit.clicked.connect( self.cb_closeMoveMotor) self.exit.setShortcut( "Alt+x") self.w_testMv = Qt.QPushButton(self.tr("Test: mv")) self.w_testMv.setToolTip( "move up by 1, then down again") self.statusBar.addWidget( self.w_testMv) self.w_testMv.clicked.connect( self.cb_testMv) self.w_testDscan = Qt.QPushButton(self.tr("Test: dscan")) self.w_testDscan.setToolTip( "exec dscan") self.statusBar.addWidget( self.w_testDscan) self.w_testDscan.clicked.connect( self.cb_testDscan) # # the update timer, don't want to poll all devices at high speed # self.updateTimer = QtCore.QTimer(self) self.updateTimer.timeout.connect( self.cb_refresh) def prepareMenuBar( self): self.fileMenu = self.menuBar.addMenu('&File') self.exitAction = Qt.QAction('E&xit', self) self.exitAction.setStatusTip('Exit application') self.exitAction.triggered.connect(Qt.qApp.quit) self.fileMenu.addAction( self.exitAction ) def updateWidgets( self): # # fill the widgets # self.w_alias.setText( self.dev[ 'name']) self.w_motorPosition.setModel( '%s/position' % self.dev[ 'device']) self.w_motorPosition.setBgRole( 'state') self.w_stop.setToolTip( "Stop %s" % self.dev[ 'name']) self.setSliderScale() self.w_motorLimitMin.setModel( '%s/unitlimitmin' % self.dev[ 'device']) self.w_motorLimitMax.setModel( '%s/unitlimitmax' % self.dev[ 'device']) def cb_refresh(): self.logWidget.append( "this is refresh") def cb_testMv( self): ”' move up by 1 then down again ”' self.flagStopped = False oldPos = self.motor.position self.logWidget.append( "mv up by 1, then back down") self.motor.position += 1 while self.motor.state() == PyTango.DevState.MOVING: self.logWidget.append( "testMv: moving UP %s %g" % (self.dev[ 'name'], self.motor.position)) QtGui.qApp.processEvents() time.sleep( 0.2) if self.flagStopped: self.logWidget.append( "testMv: sensed flagStopped") return self.motor.position = oldPos while self.motor.state() == PyTango.DevState.MOVING: self.logWidget.append( "testMv: moving DOWN %s %g" % (self.dev[ 'name'], self.motor.position)) QtGui.qApp.processEvents() time.sleep( 0.2) def cb_testDscan( self): ”' exec: dscan d1_mot65 -1 1 10 0.1 ”' self.flagStopped = False door = PyTango.DeviceProxy( HasyUtils.getDoorNames()[0]) cmd = ["dscan", "d1_mot65", "-1", "1", "10", "0.1"] self.logWidget.append( str(cmd)) door.runmacro( cmd) while door.state() == PyTango.DevState.RUNNING: QtGui.qApp.processEvents() time.sleep( 0.2) self.logWidget.append( "dscan done") def cb_abort( self): self.logWidget.append( "abort") door = PyTango.DeviceProxy( HasyUtils.getDoorNames()[0]) door.abort() def cb_sliderReleased( self): value = self.w_slider.value() if self.motor.state() == PyTango.DevState.MOVING: execStopMove( self.dev) while self.motor.state() == PyTango.DevState.MOVING: time.sleep(0.01) posReq = (self.motor.unitlimitmax - self.motor.unitlimitmin)*value/\ float(SLIDER_RESOLUTION) + self.motor.unitlimitmin self.moveTarget( posReq) def cb_sliderValueChanged( self, value): # # set the slider position label on valueChanged # posSlider = (self.motor.unitlimitmax - self.motor.unitlimitmin)*value/\ float(SLIDER_RESOLUTION) + self.motor.unitlimitmin if self.w_sliderPosition: self.w_sliderPosition.setText( "%g" % posSlider) def setSliderScale( self): self.w_slider.setMinimum( 0) self.w_slider.setMaximum( int(SLIDER_RESOLUTION)) try: value = int( float(SLIDER_RESOLUTION)*(self.motor.position - self.motor.unitlimitmin)/ (self.motor.unitlimitmax - self.motor.unitlimitmin)) self.w_slider.setValue( value) except: self.logWidget.append( "setSliderScale: Failed to set slider scale") def closeEvent( self, e): ”' the closeEvent is called when the window is closed by clicking the X at the right-upper corner of the frame ”' self.cb_closeMoveMotor() #e.ignore() def cb_closeMoveMotor( self): if self.motor.state() == PyTango.DevState.MOVING: print( "cb_closeMoveMotor: stopping motor") self.motor.stopMove() while self.motor.state() == PyTango.DevState.MOVING: time.sleep(0.01) if hasattr( self, "scan"): del self.scan self.close() def cb_stopMove( self): ”' stop the motor, if MOVING, and waits until is stopped ”' self.logWidget.append( "stopMove") self.flagStopped = True if self.motor.state() == PyTango.DevState.MOVING: self.motor.stopMove() while self.motor.state() == PyTango.DevState.MOVING: time.sleep(0.01) def moveTo( self): ”' read the moveToLine widget and move the motor ”' temp = self.moveToLine.text() self.moveToLine.clear() if len(temp) == 0: return self.moveTarget( float(temp)) def moveTarget( self, posReq): ”' moves a motor to the requested position, checks the status before and prints an error, if the move does not start properly ”' if self.motor.state() != PyTango.DevState.ON: QtGui.QMessageBox.critical(self, 'Error', "moveTarget: state != ON (%s)" % self.dev[ 'name'], QtGui.QMessageBox.Ok) return try: self.motor.position = posReq except Exception as e: self.logWidget.append( "%s, setting the position causes an error" % (self.dev[ 'name'])) for arg in e.args: if hasattr( arg, 'desc'): self.logWidget.append( " desc: %s" % arg.desc) self.logWidget.append( " origin: %s" % arg.origin) self.logWidget.append( " reason: %s" % arg.reason) self.logWidget.append( "") else: self.logWidget.append( repr( e)) return def main(): app = TaurusApplication( sys.argv) dev = { 'control': 'tango', 'name': 'd1_mot65', 'hostname': 'haspp99:10000', 'module': 'oms58', 'device': 'p99/motor/d1.65', 'type': 'stepping_motor', 'flagPoolMotor': False} try: dev[ 'proxy'] = PyTango.DeviceProxy( dev['device']) except: print( "failed to create proxy to", dev['name']) return changeDefaultPollingPeriod( 100) w = moveMotor( dev) w.show() sys.exit( app.exec_()) if __name__ == "__main__": main()