Don’t be scared by the graph. Probably most of the packages are already installed. The current PyTango version has four major dependencies:
python (>= 2.4) (http://www.python.org/)
omniORB (http://omniorb.sourceforge.net/)
Tango (>= 7.1.0) (http://www.tango-controls.org/) (really recommended 7.1.1)
if python >= 2.6.3 then: boost-python >= 1.41 else: boost-python >= 1.33 We strongly recommend always using >= 1.41
plus one optional dependency (activated by default) on:
Note
For the provided windows binary, numpy is MANDATORY!
The latest binaries for PyTango can be found at: http://www.tango-controls.org/download under the tango bindings section.
The PyTango team does not provide a precompiled binary for Linux since this would mean having to provide 12 different binaries: one for each major python version (2.4, 2.5, 2.6, 2.7, 3.0 and 3.1) times 2 for both 32bits and 64bits.
PyTango team provides a binary PyTango distributable for Windows XP/Vista 32bits for usage with python 2.6.
The binary comes with its’s own boost-python, omniORB and Tango DLLs
version | Includes the following DLLs |
---|---|
7.1.0 |
|
7.1.0 rc1 |
|
The binary was compiled with numpy dependency therefore you need to have numpy* installed in order to use numpy
Since PyTango 7 the build system used to compile PyTango is the standard python distutils.
Besides the binaries for the four dependencies mentioned above, you also need the development files for the respective libraries.
PyTango has a dependency on the boost python library (>= 1.33). This means that the shared library file libboost-python.so must be accessible to the compilation command.
Note
If you use python >= 2.6.3 you MUST install boost python >= 1.41
Most linux distributions today provide a boost python package.
Furthermore, in order to be able to build PyTango, you also need the include headers of boost python. They are normaly provided by a package called boost_python-dev.
If, for some reason, you need to compile and install boost python, here is a quick recipie:
Download latest boost tar.gz file and extract it
Download latest bjam (most linux distributions have a bjam package. If not, sourceforge provides a binary for many platforms)
build and/or install:
Simple build: in the root directory where you extracted boost type:
bjam --with-python toolset=gcc variant=release threading=multi link=shared
this will produce in bin.v2/libs/python/build/gcc-<gcc_ver>/release/threading-multi a file called libboost_python-gcc<gcc_ver>-mt-<boost_ver>.so.<boost_python_ver>
Install (you may need administrator permissions to do so):
bjam --with-python toolset=gcc variant=release threading=multi link=shared install
Install in a different directory (<install_dir>):
bjam --with-python toolset=gcc variant=release threading=multi link=shared install --prefix=<install_dir>
The second step is to make sure the three/four libraries (omniORB, tango, boost python and/or numpy) are accessible to the compilation command. So, for example, if you installed:
boost python under /home/homer/local
omniORB under /home/homer/local1
tango under /home/homer/local2
numpy under /usr/lib/python2.6/site-packages/numpy
you must export the three environment variables:
export BOOST_ROOT=/home/homer/local
export OMNI_ROOT=/home/homer/local1
export TANGO_ROOT=/home/homer/local2
# in openSUSE 11.1 this is the default base location for the include files
export NUMPY_ROOT=/usr/lib/python2.6/site-packages/numpy/core
(for numpy this is the default base location for the include files. This is distribution dependent. For example, ubuntu places a numpy directory under /usr/include, so exporting NUMPY_ROOT is not necessary for this distribution)
For the libraries that were installed in the default system directory (/usr or /usr/local) the above lines are not necessary.
Finally:
python setup.py build
sudo python setup.py install
Or if you whish to install in a different directory:
python setup.py build
python setup.py install --prefix=/home/homer/local
Or if you wish to use your own private python distribution:
/home/homer/bin/python setup.py build
/home/homer/bin/python setup.py install
For the last case above don’t forget that boost python should have also been previously compiled with this private python distribution.
>>> import PyTango
>>> print PyTango.Release.version
7.1.0
Start a python console and type:
1 2 3 4 5 6 7 | >>> import PyTango
>>> PyTango.__version__
'7.1.0'
>>> PyTango.__version_number__
710
>>> PyTango.__version_description__
'This version implements the C++ Tango 7.1 API.'
|
or alternatively:
1 2 3 4 5 6 7 | >>> import PyTango
>>> PyTango.Release.version
'7.1.0'
>>> PyTango.Release.version_number
710
>>> PyTango.Release.version_description
'This version implements the C++ Tango 7.1 API.'
|
From a client (This is only possible since PyTango 7.0.0)
>>> import PyTango.constants
>>> PyTango.constants.TgLibVers
'7.1.0'
From a server you can alternatively do:
u = PyTango.Util.instance()
tg_cpp_lib_ver = u.get_tango_lib_release()
One of the most basic examples is to get a reference to a device and determine if it is running or not:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | from PyTango import *
import sys, os, time
# Protect the script from Exceptions
try:
# Get proxy on the tangotest1 device
print "Getting DeviceProxy "
tangotest = DeviceProxy("tango/tangotest/1")
# ping it
print tangotest.ping()
# get the state
print tangotest.state()
# First use the classical command_inout way to execute the DevString command
# (DevString in this case is a command of the TangoTest device)
result= tangotest.command_inout("DevString", "First hello to device")
print "Result of execution of DevString command=", result
# the same with a Device specific command
result= tangotest.DevString("Second Hello to device")
print "Result of execution of DevString command=", result
# Please note that argin argument type is automagically managed by python
result= tangotest.DevULong(12456)
print "Result of execution of Status command=", result
# Catch Tango and Systems Exceptions
except:
print "Failed with exception !"
print sys.exc_info()[0]
|
As you can see in the following example, when scalar types are used, the Tango binding automagically manages the data types, and writing scripts is quite easy:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | from PyTango import *
import sys, os, time
tangotest = DeviceProxy("tango/tangotest/1")
# First use the classical command_inout way to execute the DevString command
# (DevString in this case is a command of the TangoTest device)
result= tangotest.command_inout("DevString", "First hello to device")
print "Result of execution of DevString command=", result
# the same with a Device specific command
result= tangotest.DevString("Second Hello to device")
print "Result of execution of DevString command=", result
# Please note that argin argument type is automagically managed by python
result= tangotest.DevULong(12456)
print "Result of execution of Status command=", result
|
In this case you have to use put your arguments data in the correct python structures:
1 2 3 4 5 6 7 8 9 10 11 12 | from PyTango import *
import sys, os, time
print "Getting DeviceProxy "
tango_test = DeviceProxy("tango/tangotest/1")
# The input argument is a DevVarLongStringArray
# so create the argin variable containing
# an array of longs and an array of strings
argin = ([1,2,3], ["Hello", "TangoTest device"])
result= tango_test.DevVarLongArray(argin)
print "Result of execution of DevVarLongArray command=", result
|
Basic read/write attribute operations:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | from PyTango import *
import sys, os, time
#Read a scalar attribute
scalar=tangotest.read_attribute("long_scalar")
print "attribute value", scalar.value
#Read a spectrum attribute
spectrum=tangotest.read_attribute("double_spectrum")
print "attribute value", spectrum.value
# Write a scalar attribute so use the scalar structure
print "Writing attributes"
# Write a scalar attribute so use the scalar structure
scalar.value = 18
print "attribute scalar ", scalar
print "Writing scalar attributes"
tangotest.write_attribute(scalar)
# Write a scalar attribute so use the scalar structure
spectrum.value = [1.2,3.2,12.3]
print "attribute spectrum ", spectrum
print "Writing spectrum attributes"
tangotest.write_attribute(spectrum)
|
Defining devices in the Tango DataBase:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | from PyTango import *
import sys, os, time
# A reference on the DataBase
db = Database()
# The 3 devices name we want to create
# Note: these 3 devices will be served by the same DServer
new_device_name1="px1/tdl/mouse1"
new_device_name2="px1/tdl/mouse2"
new_device_name3="px1/tdl/mouse3"
# Define the Tango Class served by this DServer
new_device_info_mouse = DbDevInfo()
new_device_info_mouse._class = "Mouse"
new_device_info_mouse.server = "ds_Mouse/server_mouse"
# add the first device
print "Creation Device:" , new_device_name1
new_device_info_mouse.name = new_device_name1
db.add_device(new_device_info_mouse)
# add the next device
print "Creation Device:" , new_device_name2
new_device_info_mouse.name = new_device_name2
db.add_device(new_device_info_mouse)
# add the third device
print "Creation Device:" , new_device_name3
new_device_info_mouse.name = new_device_name3
db.add_device(new_device_info_mouse)
|
A more complex example using python subtilities. The following python script example (containing some functions and instructions manipulating a Galil motor axis device server) gives an idea of how the Tango API should be accessed from Python:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | from PyTango import *
import sys, os, time
# connecting to the motor axis device
axis1 = DeviceProxy ("microxas/motorisation/galilbox")
# Getting Device Properties
property_names = ["AxisBoxAttachement",
"AxisEncoderType",
"AxisNumber",
"CurrentAcceleration",
"CurrentAccuracy",
"CurrentBacklash",
"CurrentDeceleration",
"CurrentDirection",
"CurrentMotionAccuracy",
"CurrentOvershoot",
"CurrentRetry",
"CurrentScale",
"CurrentSpeed",
"CurrentVelocity",
"EncoderMotorRatio",
"logging_level",
"logging_target",
"UserEncoderRatio",
"UserOffset"]
axis_properties = axis1.get_property(property_names)
for prop in axis_properties.keys():
print "%s: %s" % (prop, axis_properties[prop][0])
# Changing Properties
axis_properties["AxisBoxAttachement"] = ["microxas/motorisation/galilbox"]
axis_properties["AxisEncoderType"] = ["1"]
axis_properties["AxisNumber"] = ["6"]
axis1.put_property(axis_properties)
# Reading attributes and storing them in a python dictionary
att_dict = {}
att_list = axis.get_attribute_list()
for att in att_list:
att_val = axis.read_attribute(att)
print "%s: %s" % (att,att_val.value)
att_dict[att] = att_val
# Changing some attribute values
attributes["AxisBackslash"].value = 0.5
axis1.write_attribute(attributes["AxisBackslash"])
attributes["AxisDirection"].value = 1.0
axis1.write_attribute(attributes["AxisDirection"])
attributes["AxisVelocity"].value = 1000.0
axis1.write_attribute(attributes["AxisVelocity"])
attributes["AxisOvershoot"].value = 500.0
axis1.write_attribute(attributes["AxisOvershoot"])
# Testing some device commands
pos1=axis1.read_attribute("AxisCurrentPosition")
axis1.command_inout("AxisBackward")
while pos1.value > 1000.0:
pos1=axis1.read_attribute("AxisCurrentPosition")
print "position axis 1 = ",pos1.value
axis1.command_inout("AxisStop")
|
To write a tango device server in python, you need to import two modules in your script which are:
The following in the python script for a Tango device server with two commands and two attributes. The commands are:
The attributes are:
The following code is the complete device server code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 | import PyTango
import sys
class PyDsExp(PyTango.Device_3Impl):
def __init__(self,cl,name):
PyTango.Device_3Impl.__init__(self,cl,name)
self.debug_stream('In PyDsExp __init__')
PyDsExp.init_device(self)
def init_device(self):
self.debug_stream('In Python init_device method')
self.set_state(PyTango.DevState.ON)
self.attr_short_rw = 66
self.attr_long = 1246
#------------------------------------------------------------------
def delete_device(self):
self.debug_stream('[delete_device] for device %s ' % self.get_name())
#------------------------------------------------------------------
# COMMANDS
#------------------------------------------------------------------
def is_IOLong_allowed(self):
return self.get_state() == PyTango.DevState.ON
def IOLong(self, in_data):
self.debug_stream('[IOLong::execute] received number %s' % str(in_data))
in_data = in_data * 2;
self.debug_stream('[IOLong::execute] return number %s' % str(in_data))
return in_data;
#------------------------------------------------------------------
def is_IOStringArray_allowed(self):
return self.get_state() == PyTango.DevState.ON
def IOStringArray(self, in_data):
l = range(len(in_data)-1, -1, -1);
out_index=0
out_data=[]
for i in l:
self.debug_stream('[IOStringArray::execute] received String' % in_data[out_index])
out_data.append(in_data[i])
self.debug_stream('[IOStringArray::execute] return String %s' %out_data[out_index])
out_index += 1
self.y = out_data
return out_data
#------------------------------------------------------------------
# ATTRIBUTES
#------------------------------------------------------------------
def read_attr_hardware(self, data):
self.debug_stream('In read_attr_hardware')
#------------------------------------------------------------------
def read_Long_attr(self, the_att):
self.debug_stream('[PyDsExp::read_attr] attribute name Long_attr')
# Before PyTango 7.0.0
#PyTango.set_attribute_value(the_att, self.attr_long)
# Now:
the_att.set_value(self.attr_long)
#------------------------------------------------------------------
def read_Short_attr_rw(self, the_att):
self.debug_stream('[PyDsExp::read_attr] attribute name Short_attr_rw')
# Before PyTango 7.0.0
#PyTango.set_attribute_value(the_att, self.attr_short_rw)
# Now:
the_att.set_value(self.attr_short_rw)
#------------------------------------------------------------------
def write_Short_attr_rw(self, the_att):
self.debug_stream('In write_Short_attr_rw for attribute %s' % the_att.get_name())
# Before PyTango 7.0.0
#data = []
#PyTango.get_write_value(the_att, data)
# Now:
data = the_att.get_write_value()
self.attr_short_rw = data[0]
#------------------------------------------------------------------
# CLASS
#------------------------------------------------------------------
class PyDsExpClass(PyTango.DeviceClass):
def __init__(self, name):
PyTango.DeviceClass.__init__(self, name)
self.set_type("TestDevice")
print 'In PyDsExpClass __init__'
cmd_list = { 'IOLong' : [ [ PyTango.ArgType.DevLong, "Number" ],
[ PyTango.ArgType.DevLong, "Number * 2" ] ],
'IOStringArray' : [ [ PyTango.ArgType.DevVarStringArray, "Array of string" ],
[ PyTango.ArgType.DevVarStringArray, "This reversed array"] ],
}
attr_list = { 'Long_attr' : [ [ PyTango.ArgType.DevLong ,
PyTango.AttrDataFormat.SCALAR ,
PyTango.AttrWriteType.READ],
{ 'min alarm' : 1000, 'max alarm' : 1500 } ],
'Short_attr_rw' : [ [ PyTango.ArgType.DevShort,
PyTango.AttrDataFormat.SCALAR,
PyTango.AttrWriteType.READ_WRITE ] ]
}
if __name__ == '__main__':
try:
py = PyTango.Util(sys.argv)
py.add_TgClass(PyDsExpClass, PyDsExp, 'PyDsExp')
U = PyTango.Util.instance()
U.server_init()
U.server_run()
except PyTango.DevFailed,e:
print '-------> Received a DevFailed exception:',e
except Exception,e:
print '-------> An unforeseen exception occured....',e
|