#!/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()