summaryrefslogtreecommitdiff
path: root/doc/source/devel/howto_controllers
diff options
context:
space:
mode:
Diffstat (limited to 'doc/source/devel/howto_controllers')
-rw-r--r--doc/source/devel/howto_controllers/howto_0dcontroller.rst37
-rw-r--r--doc/source/devel/howto_controllers/howto_1dcontroller.rst37
-rw-r--r--doc/source/devel/howto_controllers/howto_2dcontroller.rst37
-rw-r--r--doc/source/devel/howto_controllers/howto_controller.rst533
-rw-r--r--doc/source/devel/howto_controllers/howto_countertimercontroller.rst105
-rw-r--r--doc/source/devel/howto_controllers/howto_ioregistercontroller.rst37
-rw-r--r--doc/source/devel/howto_controllers/howto_motorcontroller.rst694
-rw-r--r--doc/source/devel/howto_controllers/howto_pseudocountercontroller.rst37
-rw-r--r--doc/source/devel/howto_controllers/howto_pseudomotorcontroller.rst37
-rw-r--r--doc/source/devel/howto_controllers/index.rst32
-rw-r--r--doc/source/devel/howto_controllers/sf_ct_ctrl.py122
-rw-r--r--doc/source/devel/howto_controllers/sf_motor_ctrl.py141
-rw-r--r--doc/source/devel/howto_controllers/springfieldlib.py653
13 files changed, 0 insertions, 2502 deletions
diff --git a/doc/source/devel/howto_controllers/howto_0dcontroller.rst b/doc/source/devel/howto_controllers/howto_0dcontroller.rst
deleted file mode 100644
index 23c5af66..00000000
--- a/doc/source/devel/howto_controllers/howto_0dcontroller.rst
+++ /dev/null
@@ -1,37 +0,0 @@
-.. currentmodule:: sardana.pool.controller
-
-.. _sardana-0dcontroller-howto-basics:
-
-============================
-How to write a 0D controller
-============================
-
-The basics
-----------
-
-.. todo:: document 0D controller howto
-
-.. _ALBA: http://www.cells.es/
-.. _ANKA: http://http://ankaweb.fzk.de/
-.. _ELETTRA: http://http://www.elettra.trieste.it/
-.. _ESRF: http://www.esrf.eu/
-.. _FRMII: http://www.frm2.tum.de/en/index.html
-.. _HASYLAB: http://hasylab.desy.de/
-.. _MAX-lab: http://www.maxlab.lu.se/maxlab/max4/index.html
-.. _SOLEIL: http://www.synchrotron-soleil.fr/
-
-.. _Tango: http://www.tango-controls.org/
-.. _Taco: http://www.esrf.eu/Infrastructure/Computing/TACO/
-.. _PyTango: http://packages.python.org/PyTango/
-.. _Taurus: http://packages.python.org/taurus/
-.. _QTango: http://www.tango-controls.org/download/index_html#qtango3
-.. _Qt: http://qt.nokia.com/products/
-.. _PyQt: http://www.riverbankcomputing.co.uk/software/pyqt/
-.. _PyQwt: http://pyqwt.sourceforge.net/
-.. _Python: http://www.python.org/
-.. _IPython: http://ipython.org/
-.. _ATK: http://www.tango-controls.org/Documents/gui/atk/tango-application-toolkit
-.. _Qub: http://www.blissgarden.org/projects/qub/
-.. _numpy: http://numpy.scipy.org/
-.. _SPEC: http://www.certif.com/
-.. _EPICS: http://www.aps.anl.gov/epics/
diff --git a/doc/source/devel/howto_controllers/howto_1dcontroller.rst b/doc/source/devel/howto_controllers/howto_1dcontroller.rst
deleted file mode 100644
index 634654e7..00000000
--- a/doc/source/devel/howto_controllers/howto_1dcontroller.rst
+++ /dev/null
@@ -1,37 +0,0 @@
-.. currentmodule:: sardana.pool.controller
-
-.. _sardana-1dcontroller-howto-basics:
-
-============================
-How to write a 1D controller
-============================
-
-The basics
-----------
-
-.. todo:: document 1D controller howto
-
-.. _ALBA: http://www.cells.es/
-.. _ANKA: http://http://ankaweb.fzk.de/
-.. _ELETTRA: http://http://www.elettra.trieste.it/
-.. _ESRF: http://www.esrf.eu/
-.. _FRMII: http://www.frm2.tum.de/en/index.html
-.. _HASYLAB: http://hasylab.desy.de/
-.. _MAX-lab: http://www.maxlab.lu.se/maxlab/max4/index.html
-.. _SOLEIL: http://www.synchrotron-soleil.fr/
-
-.. _Tango: http://www.tango-controls.org/
-.. _Taco: http://www.esrf.eu/Infrastructure/Computing/TACO/
-.. _PyTango: http://packages.python.org/PyTango/
-.. _Taurus: http://packages.python.org/taurus/
-.. _QTango: http://www.tango-controls.org/download/index_html#qtango3
-.. _Qt: http://qt.nokia.com/products/
-.. _PyQt: http://www.riverbankcomputing.co.uk/software/pyqt/
-.. _PyQwt: http://pyqwt.sourceforge.net/
-.. _Python: http://www.python.org/
-.. _IPython: http://ipython.org/
-.. _ATK: http://www.tango-controls.org/Documents/gui/atk/tango-application-toolkit
-.. _Qub: http://www.blissgarden.org/projects/qub/
-.. _numpy: http://numpy.scipy.org/
-.. _SPEC: http://www.certif.com/
-.. _EPICS: http://www.aps.anl.gov/epics/
diff --git a/doc/source/devel/howto_controllers/howto_2dcontroller.rst b/doc/source/devel/howto_controllers/howto_2dcontroller.rst
deleted file mode 100644
index bc73fceb..00000000
--- a/doc/source/devel/howto_controllers/howto_2dcontroller.rst
+++ /dev/null
@@ -1,37 +0,0 @@
-.. currentmodule:: sardana.pool.controller
-
-.. _sardana-2dcontroller-howto-basics:
-
-============================
-How to write a 2D controller
-============================
-
-The basics
-----------
-
-.. todo:: document 2D controller howto
-
-.. _ALBA: http://www.cells.es/
-.. _ANKA: http://http://ankaweb.fzk.de/
-.. _ELETTRA: http://http://www.elettra.trieste.it/
-.. _ESRF: http://www.esrf.eu/
-.. _FRMII: http://www.frm2.tum.de/en/index.html
-.. _HASYLAB: http://hasylab.desy.de/
-.. _MAX-lab: http://www.maxlab.lu.se/maxlab/max4/index.html
-.. _SOLEIL: http://www.synchrotron-soleil.fr/
-
-.. _Tango: http://www.tango-controls.org/
-.. _Taco: http://www.esrf.eu/Infrastructure/Computing/TACO/
-.. _PyTango: http://packages.python.org/PyTango/
-.. _Taurus: http://packages.python.org/taurus/
-.. _QTango: http://www.tango-controls.org/download/index_html#qtango3
-.. _Qt: http://qt.nokia.com/products/
-.. _PyQt: http://www.riverbankcomputing.co.uk/software/pyqt/
-.. _PyQwt: http://pyqwt.sourceforge.net/
-.. _Python: http://www.python.org/
-.. _IPython: http://ipython.org/
-.. _ATK: http://www.tango-controls.org/Documents/gui/atk/tango-application-toolkit
-.. _Qub: http://www.blissgarden.org/projects/qub/
-.. _numpy: http://numpy.scipy.org/
-.. _SPEC: http://www.certif.com/
-.. _EPICS: http://www.aps.anl.gov/epics/
diff --git a/doc/source/devel/howto_controllers/howto_controller.rst b/doc/source/devel/howto_controllers/howto_controller.rst
deleted file mode 100644
index 508ca916..00000000
--- a/doc/source/devel/howto_controllers/howto_controller.rst
+++ /dev/null
@@ -1,533 +0,0 @@
-.. currentmodule:: sardana.pool.controller
-
-.. _sardana-controller-howto-whatis:
-
-====================
-What is a controller
-====================
-
-A controller in sardana is a piece of software capable of *translating*
-between the sardana :term:`API` and a specific hardware :term:`API`. Sardana
-expects a controller to obey a specific :term:`API` in order to be able to
-properly configure and operate with it. The hardware :term:`API` used by the
-controller could be anything, from a pure serial line to shared memory or a
-remote server written in Tango_, Taco_ or even EPICS_.
-
-Controllers can only be written in Python_ (in future also C++ will be
-possible). A controller **must** be a :term:`class` inheriting from one of the
-existing controller types:
-
-.. hlist::
- :columns: 3
-
- - :class:`MotorController`
- - :class:`CounterTimerController`
- - :class:`ZeroDController`
- - :class:`OneDController`
- - :class:`TwoDController`
- - :class:`IORegisterController`
-
- - :class:`PseudoMotorController`
- - :class:`PseudoCounterController`
-
-A controller is designed to incorporate a set of generic individual elements.
-Each element has a corresponding *axis*. For example, in a motor
-controller the elements will be motors, but in a counter/timer controller the
-elements will be experimental channels.
-
-Some controller classes are designed to target a specific type of hardware.
-Other classes of controllers, the *pseudo* classes, are designed to provide a
-high level view over a set of underlying lower level controller elements.
-
-We will focus first on writing low level hardware controllers since they
-share some of the :term:`API` and after on the *pseudo* controllers.
-
-.. _sardana-controller-howto-basics:
-
-Controller - The basics
------------------------
-
-The first thing to do is to import the necessary symbols from sardana library.
-As you will see, most symbols can be imported through the
-:mod:`sardana.pool.controller` module:
-
-.. code-block:: python
-
- import springfieldlib
-
- from sardana.pool.controller import MotorController
-
- class SpringfieldMotorController(MotorController):
- """A motor controller intended from demonstration purposes only"""
- pass
-
-The common :term:`API` to all low level controllers includes the set of methods
-to:
-
- #. construct the controller
- #. add/delete a controller element [#f1]_
- #. obtain the state of controller element(s) [#f2]_
- #. define, set and get extra axis attributes
- #. define, set and get extra controller attributes
- #. define, set and get extra controller properties
-
-In the following chapters the examples will be based on a motor controller
-scenario.
-
-The examples use a :mod:`springfieldlib` module which emulates a motor hardware
-access library.
-
-The :mod:`springfieldlib` can be downloaded from
-:download:`here <springfieldlib.py>`.
-
-The Springfield motor controller can be downloaded from
-:download:`here <sf_motor_ctrl.py>`.
-
-.. _sardana-controller-howto-constructor:
-
-Constructor
-~~~~~~~~~~~
-
-The constructor consists of the
-:meth:`~sardana.pool.controller.Controller.__init__` method. This method is
-called when you create a new controller of that type and every time the sardana
-server is started. It will also be called if the controller code has changed
-on the file and the new code is reloaded into sardana.
-
-It is **NOT** mandatory to override the :meth:`~sardana.pool.controller.Controller.__init__`
-from :class:`~sardana.pool.controller.MotorController` . Do it only
-if you need to add some initialization code. If you do it, it is **very important**
-to follow the two rules:
-
- #. use the method signature: ``__init__(self, inst, props, *args, **kwargs)``
- #. always call the super class constructor
-
-The example shows how to implement a constructor for a motor controller:
-
-.. code-block:: python
- :emphasize-lines: 3
-
- class SpringfieldMotorController(MotorController):
-
- def __init__(self, inst, props, *args, **kwargs):
- super(SpringfieldMotorController, self).__init__(inst, props, *args, **kwargs)
-
- # initialize hardware communication
- self.springfield = springfieldlib.SpringfieldMotorHW()
-
- # do some initialization
- self._motors = {}
-
-.. _sardana-controller-howto-add-delete:
-
-Add/Delete axis
-~~~~~~~~~~~~~~~
-
-Each individual element in a controller is called *axis*. An axis is represented
-by a number. A controller can support one or more axes. Axis numbers don't need
-to be sequencial. For example, at one time you may have created for your motor
-controller instance only axis 2 and 5.
-
-Two methods are called when creating or removing an element from a controller.
-These methods are :meth:`~sardana.pool.controller.Controller.AddDevice` and
-:meth:`~sardana.pool.controller.Controller.DeleteDevice`. The
-:meth:`~sardana.pool.controller.Controller.AddDevice` method is called when a
-new axis belonging to the controller is created in sardana. The
-:meth:`~sardana.pool.controller.Controller.DeleteDevice` method is
-called when an axis belonging to the controller is removed from sardana.
-The example shows an example how to implement these methods on a motor
-controller:
-
-.. code-block:: python
- :emphasize-lines: 3, 6
-
- class SpringfieldMotorController(MotorController):
-
- def AddDevice(self, axis):
- self._motors[axis] = True
-
- def DeleteDevice(self, axis):
- del self._motor[axis]
-
-.. _sardana-controller-howto-axis-state:
-
-Get axis state
-~~~~~~~~~~~~~~
-
-To get the state of an axis, sardana calls the
-:meth:`~sardana.pool.controller.Controller.StateOne` method. This method
-receives an axis as parameter and should return either:
-
- - state (:obj:`~sardana.sardanadefs.State`) or
- - a sequence of two elements:
- - state (:obj:`~sardana.sardanadefs.State`)
- - status (:obj:`str`)
-
-(For motor controller see :ref:`get motor state <sardana-motorcontroller-howto-axis-state>` ):
-
-The state should be a member of :obj:`~sardana.sardanadefs.State` (For backward
-compatibility reasons, it is also supported to return one of
-:class:`PyTango.DevState`). The status could be any string.
-
-If you return a :obj:`~sardana.sardanadefs.State` object, sardana will compose a
-status string with:
-
- <axis name> is in <state name>
-
-Here is an example of the possible implementation of
-:meth:`~sardana.pool.controller.Controller.StateOne` :
-
-.. code-block:: python
- :emphasize-lines: 11
-
- from sardana import State
-
- class SpringfieldMotorController(MotorController):
-
- StateMap = {
- 1 : State.On,
- 2 : State.Moving,
- 3 : State.Fault,
- }
-
- def StateOne(self, axis):
- springfield = self.springfield
- state = self.StateMap[ springfield.getState(axis) ]
- status = springfield.getStatus(axis)
- return state, status
-
-
-.. _sardana-controller-howto-axis-attributes:
-
-Extra axis attributes
-~~~~~~~~~~~~~~~~~~~~~
-
-Each axis is associated a set of standard attributes. These attributes depend
-on the type of controller (example, a motor will have velocity, acceleration but
-a counter won't).
-
-Additionally, you can specify an additional set of extra attributes on each axis.
-
-Lets suppose that a Springfield motor controller can do close loop on hardware.
-We could define an extra motor attribute on each axis that (de)actives close
-loop on demand.
-
-The first thing to do is to specify which are the extra attributes.
-This is done through the :attr:`~sardana.pool.controller.Controller.axis_attributes`.
-This is basically a dictionary were the keys are attribute names and the value
-is a dictionary describing the folowing properties for each attribute:
-
-===================== ========= ============================================ ======================================================= ===============================================
-config. parameter Mandatory Key Default value Example
-===================== ========= ============================================ ======================================================= ===============================================
-data type & format Yes :obj:`~sardana.pool.controller.Type` --- :obj:`int`
-data access No :obj:`~sardana.pool.controller.Access` :obj:`~sardana.pool.controller.Access.ReadWrite` :obj:`~sardana.pool.controller.Access.ReadOnly`
-description No :obj:`~sardana.pool.controller.Description` "" (empty string) "the motor encoder source"
-default value No :obj:`~sardana.pool.controller.DefaultValue` --- 12345
-getter method name No :obj:`~sardana.pool.controller.FGet` "get" + <name> "getEncoderSource"
-setter method name No :obj:`~sardana.pool.controller.FSet` "set" + <name> "setEncoderSource"
-memorize value No :obj:`~sardana.pool.controller.Memorize` :obj:`~sardana.pool.controller.Memorized` :obj:`~sardana.pool.controller.NotMemorized`
-max dimension size No :obj:`~sardana.pool.controller.MaxDimSize` Scalar: ``()``; 1D: ``(2048,)``; 2D: ``(2048, 2048)`` ``(2048,)``
-===================== ========= ============================================ ======================================================= ===============================================
-
-Here is an example of how to specify the scalar, boolean, read-write *CloseLoop*
-extra attribute in a Springfield motor controller:
-
-.. code-block:: python
- :emphasize-lines: 6, 14, 17
-
- from sardana import DataAccess
- from sardana.pool.controller import Type, Description, DefaultValue, Access, FGet, FSet
-
- class SpringfieldMotorController(MotorController):
-
- axis_attributes = {
- "CloseLoop" : {
- Type : bool,
- Description : "(de)activates the motor close loop algorithm",
- DefaultValue : False,
- },
- }
-
- def getCloseLoop(self, axis):
- return self.springfield.isCloseLoopActive(axis)
-
- def setCloseLoop(self, axis, value):
- self.springfield.setCloseLoop(axis, value)
-
-When sardana needs to read the close loop value, it will first check if the
-controller has the method specified by the :obj:`~sardana.pool.controller.FGet`
-keyword (we didn't specify it in
-:attr:`~sardana.pool.controller.Controller.axis_attributes` so it defaults to
-*getCloseLoop*). It will then call this controller method which
-should return a value compatible with the attribute data type.
-
-As an alternative, to avoid filling the controller code with pairs of get/set
-methods, you can choose not to write the getCloseLoop and setCloseLoop methods.
-This will trigger sardana to call the
-:meth:`~sardana.pool.controller.Controller.GetAxisExtraPar`
-/:meth:`~sardana.pool.controller.Controller.SetAxisExtraPar` pair of methods.
-The disadvantage is you will end up with a forest of :keyword:`if` ...
-:keyword:`elif` ... :keyword:`else` statements. Here is the alternative
-implementation:
-
-.. code-block:: python
- :emphasize-lines: 6, 14, 18
-
- from sardana import DataAccess
- from sardana.pool.controller import Type, Description, DefaultValue, Access, FGet, FSet
-
- class SpringfieldMotorController(MotorController):
-
- axis_attributes = {
- "CloseLoop" : {
- Type : bool,
- Description : "(de)activates the motor close loop algorithm",
- DefaultValue : False,
- },
- }
-
- def GetAxisExtraPar(self, axis, parameter):
- if parameter == 'CloseLoop':
- return self.springfield.isCloseLoopActive(axis)
-
- def SetAxisExtraPar(self, axis, parameter, value):
- if parameter == 'CloseLoop':
- self.springfield.setCloseLoop(axis, value)
-
-Sardana gives you the choice: we leave it up to you to decide which is the
-better option for your specific case.
-
-.. _sardana-controller-howto-controller-attributes:
-
-Extra controller attributes
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Besides extra attributes per axis, you can also define extra attributes at the
-controller level.
-In order to do that you have to specify the extra controller attribute(s) within
-the :attr:`~sardana.pool.controller.Controller.ctrl_attributes` member. The
-syntax for this dictionary is the same as the one used for
-:attr:`~sardana.pool.controller.Controller.axis_attributes`.
-
-Here is an example on how to specify a read-only float matrix attribute called
-*ReflectionMatrix* at the controller level:
-
-.. code-block:: python
-
- class SpringfieldMotorController(MotorController):
-
- ctrl_attributes = {
- "ReflectionMatrix" : {
- Type : ( (float,), ),
- Description : "The reflection matrix",
- Access : DataAccess.ReadOnly,
- },
- }
-
- def getReflectionMatrix(self):
- return ( (1.0, 0.0), (0.0, 1.0) )
-
-Or, similar to what you can do with axis attributes:
-
-.. code-block:: python
-
- class SpringfieldMotorController(MotorController):
-
- ctrl_attributes = \
- {
- "ReflectionMatrix" : {
- Type : ( (float,), ),
- Description : "The reflection matrix",
- Access : DataAccess.ReadOnly,
- },
- }
-
- def GetCtrlPar(self, name):
- if name == "ReflectionMatrix":
- return ( (1.0, 0.0), (0.0, 1.0) )
-
-.. _sardana-controller-howto-controller-properties:
-
-Extra controller properties
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-A more static form of attributes can be defined at the controller level.
-These *properties* are loaded into the controller at the time of object
-construction. They are accessible to your controller at any time but it is
-not possible for a user from outside to modify them.
-The way to define :attr:`~sardana.pool.controller.Controller.ctrl_properties` is
-very similar to the way you define extra axis attributes or extra controller
-attributes.
-
-Here is an example on how to specify a host and port properties:
-
-.. code-block:: python
-
- class SpringfieldMotorController(MotorController):
-
- ctrl_properties = \
- {
- "host" : {
- Type : str,
- Description : "host name"
- },
- "port" : {
- Type : int,
- Description : "port number",
- DefaultValue: springfieldlib.SpringfieldMotorHW.DefaultPort
- },
- }
-
- def __init__(self, inst, props, *args, **kwargs):
- super(SpringfieldMotorController, self).__init__(inst, props, *args, **kwargs)
-
- host = self.host
- port = self.port
-
- # initialize hardware communication
- self.springfield = springfieldlib.SpringfieldMotorHW(host=host, port=port)
-
- # do some initialization
- self._motors = {}
-
-As you can see from lines 15 and 16, to access your controller properties
-simply use ``self.<property name>``. Sardana assures that every property has a
-value. In our case, when a SpringfieldMotorController is created, if port
-property is not specified by the user (example: using the ``defctrl`` macro in
-spock), sardana assignes the default value
-``springfieldlib.SpringfieldMotorHW.DefaultPort``. On the other hand, since host
-has no default value, if it is not specified by the user, sardana will complain
-and fail to create and instance of SpringfieldMotorController.
-
-.. _sardana-controller-howto-error-handling:
-
-Error handling
-~~~~~~~~~~~~~~
-
-When you write a controller it is important to properly handle errors
-(example: motor power overload, hit a limit switch, lost of communication with
-the hardware).
-
-These are the two basic sardana rules you should have in mind:
-
-#. The exceptions which are not handled by the controller are handled by sardana,
- usually by re-raising the exception (when sardana runs as a Tango_ DS a
- translation is done from the Python_ exception to a Tango_ exception).
- The :meth:`~sardana.pool.controller.Controller.StateOne` method is handled a
- little differently: the state is set to ``Fault`` and the status will contain
- the exception information.
-
-#. When the methods which are supposed to return a value (like
- :meth:`~sardana.pool.controller.Controller.GetAxisPar`) don't return a value
- compatible with the expected data type (including :obj:`None`) a
- :exc:`TypeError` exception is thrown.
-
-In every method you should carefully choose how to do handle the possible
-exceptions/errors.
-
-Usually, catch and handle is the best technique since it is the code of your
-controller which knows exactly the workings of the hardware. You can
-discriminate errors and decide a proper handle for each. Essencially, this
-technique consists of:
-
-#. catching the error (if an exception: with :keyword:`try` ... :keyword:`except`
- clause, if an expected return of a function: with a :keyword:`if` ...
- :keyword:`elif` ... :keyword:`else` statement, etc)
-
-#. raise a proper exception (could be the same exception that has been catched)
- or, if in :meth:`~sardana.pool.controller.Controller.StateOne`, return the
- apropriate error state (``Fault``, ``Alarm``) and a descriptive status.
-
-Here is an example: if the documentation of the underlying library says that:
-
- `reading the motor closeloop raises CommunicationFailed if it is not
- possible to communicate with the Springfield hardware`
-
- `reading the motor state raises MotorPowerOverload if the motors
- has a power overload or a MotorTempTooHigh when the motor
- temperature is too high`
-
-then you should handle the exception in the controller and return a proper
-state information::
-
- def getCloseLoop(self, axis):
- # Here the "proper exception" to raise in case of error is actually the
- # one that is raised from the springfield library so handling the
- # exception is transparent. Nice!
- return self.springfield.isCloseLoopActive(axis)
-
- def StateOne(self, axis):
- springfield = self.springfield
-
- try:
- state = self.StateMap[ springfield.getState(axis) ]
- status = springfield.getStatus(axis)
- except springfieldlib.MotorPowerOverload:
- state = State.Fault
- status = "Motor has a power overload"
- except springfieldlib.MotorTempTooHigh:
- temp = springfield.getTemperature(axis)
- state = State.Alarm
- status = "Motor temperature is too high (%f degrees)" % temp
-
- limit_switches = MotorController.NoLimitSwitch
- hw_limit_switches = springfield.getLimits(axis)
- if hw_limit_switches[0]:
- limit_switches |= MotorController.HomeLimitSwitch
- if hw_limit_switches[1]:
- limit_switches |= MotorController.UpperLimitSwitch
- if hw_limit_switches[2]:
- limit_switches |= MotorController.LowerLimitSwitch
- return state, status, limit_switches
-
-Hiding the exception is usually a **BAD** technique since it prevents the user
-from finding what was the cause of the problem. You should only use it in
-extreme cases (example: if there is a bug in sardana which crashes the server
-if you try to properly raise an exception, then you can **temporarely** use
-this technique until the bug is solved).
-
-Example::
-
- def getCloseLoop(self, axis):
- # BAD error handling technique
- try:
- return self.springfield.isCloseLoopActive(axis)
- except:
- pass
-
-.. rubric:: Footnotes
-
-.. [#f1] Pseudo controllers don't need to manage their individual axis. Therefore,
- for pseudos you will not implement these methods
-
-
-.. [#f2] For pseudo controllers, sardana will calculate the state of each pseudo
- axis based on the state of the elements that serve as input to the
- pseudo controller. Therefore, for pseudos you will not implement these
- methods
-
-.. _ALBA: http://www.cells.es/
-.. _ANKA: http://http://ankaweb.fzk.de/
-.. _ELETTRA: http://http://www.elettra.trieste.it/
-.. _ESRF: http://www.esrf.eu/
-.. _FRMII: http://www.frm2.tum.de/en/index.html
-.. _HASYLAB: http://hasylab.desy.de/
-.. _MAX-lab: http://www.maxlab.lu.se/maxlab/max4/index.html
-.. _SOLEIL: http://www.synchrotron-soleil.fr/
-
-.. _Tango: http://www.tango-controls.org/
-.. _Taco: http://www.esrf.eu/Infrastructure/Computing/TACO/
-.. _PyTango: http://packages.python.org/PyTango/
-.. _Taurus: http://packages.python.org/taurus/
-.. _QTango: http://www.tango-controls.org/download/index_html#qtango3
-.. _Qt: http://qt.nokia.com/products/
-.. _PyQt: http://www.riverbankcomputing.co.uk/software/pyqt/
-.. _PyQwt: http://pyqwt.sourceforge.net/
-.. _Python: http://www.python.org/
-.. _IPython: http://ipython.org/
-.. _ATK: http://www.tango-controls.org/Documents/gui/atk/tango-application-toolkit
-.. _Qub: http://www.blissgarden.org/projects/qub/
-.. _numpy: http://numpy.scipy.org/
-.. _SPEC: http://www.certif.com/
-.. _EPICS: http://www.aps.anl.gov/epics/
diff --git a/doc/source/devel/howto_controllers/howto_countertimercontroller.rst b/doc/source/devel/howto_controllers/howto_countertimercontroller.rst
deleted file mode 100644
index 22976064..00000000
--- a/doc/source/devel/howto_controllers/howto_countertimercontroller.rst
+++ /dev/null
@@ -1,105 +0,0 @@
-.. currentmodule:: sardana.pool.controller
-
-.. _sardana-countertimercontroller-howto-basics:
-
-=======================================
-How to write a counter/timer controller
-=======================================
-
-The basics
-----------
-
-An example of a hypothetical *Springfield* counter/timer controller will be build
-incrementally from scratch to aid in the explanation.
-
-By now you should have read the general controller basics chapter. You should
-be able to create a CounterTimerController with:
-
-- a proper constructor,
-- add and delete axis methods
-- get axis state
-
-
-.. code-block:: python
-
- import springfieldlib
-
- from sardana.pool.controller import CounterTimerController
-
- class SpringfieldCounterTimerController(CounterTimerController):
-
- def __init__(self, inst, props, *args, **kwargs):
- super(SpringfieldCounterTimerController, self).__init__(inst, props, *args, **kwargs)
-
- # initialize hardware communication
- self.springfield = springfieldlib.SpringfieldCounterHW()
-
- # do some initialization
- self._counters = {}
-
- def AddDevice(self, axis):
- self._counters[axis] = True
-
- def DeleteDevice(self, axis):
- del self._counters[axis]
-
- StateMap = {
- 1 : State.On,
- 2 : State.Moving,
- 3 : State.Fault,
- }
-
- def StateOne(self, axis):
- springfield = self.springfield
- state = self.StateMap[ springfield.getState(axis) ]
- status = springfield.getStatus(axis)
- return state, status
-
-The examples use a :mod:`springfieldlib` module which emulates a counter/timer
-hardware access library.
-
-The :mod:`springfieldlib` can be downloaded from
-:download:`here <springfieldlib.py>`.
-
-The Springfield counter/timer controller can be downloaded from
-:download:`here <sf_ct_ctrl.py>`.
-
-The following code describes a minimal *Springfield* base counter/timer controller
-which is able to return both the state and value of an individual counter as
-well as to start an acquisition:
-
-.. literalinclude:: sf_ct_ctrl.py
- :pyobject: SpringfieldBaseCounterTimerController
-
-This code is shown only to demonstrate the minimal controller :term:`API`.
-The advanced counter/timer controller chapters describe how to account for more
-complex behaviour like reducing the number of hardware accesses.
-
-.. todo:: finish counter/timer controller howto
-
-
-
-.. _ALBA: http://www.cells.es/
-.. _ANKA: http://http://ankaweb.fzk.de/
-.. _ELETTRA: http://http://www.elettra.trieste.it/
-.. _ESRF: http://www.esrf.eu/
-.. _FRMII: http://www.frm2.tum.de/en/index.html
-.. _HASYLAB: http://hasylab.desy.de/
-.. _MAX-lab: http://www.maxlab.lu.se/maxlab/max4/index.html
-.. _SOLEIL: http://www.synchrotron-soleil.fr/
-
-.. _Tango: http://www.tango-controls.org/
-.. _Taco: http://www.esrf.eu/Infrastructure/Computing/TACO/
-.. _PyTango: http://packages.python.org/PyTango/
-.. _Taurus: http://packages.python.org/taurus/
-.. _QTango: http://www.tango-controls.org/download/index_html#qtango3
-.. _Qt: http://qt.nokia.com/products/
-.. _PyQt: http://www.riverbankcomputing.co.uk/software/pyqt/
-.. _PyQwt: http://pyqwt.sourceforge.net/
-.. _Python: http://www.python.org/
-.. _IPython: http://ipython.org/
-.. _ATK: http://www.tango-controls.org/Documents/gui/atk/tango-application-toolkit
-.. _Qub: http://www.blissgarden.org/projects/qub/
-.. _numpy: http://numpy.scipy.org/
-.. _SPEC: http://www.certif.com/
-.. _EPICS: http://www.aps.anl.gov/epics/
diff --git a/doc/source/devel/howto_controllers/howto_ioregistercontroller.rst b/doc/source/devel/howto_controllers/howto_ioregistercontroller.rst
deleted file mode 100644
index ed669c03..00000000
--- a/doc/source/devel/howto_controllers/howto_ioregistercontroller.rst
+++ /dev/null
@@ -1,37 +0,0 @@
-.. currentmodule:: sardana.pool.controller
-
-.. _sardana-ioregistercontroller-howto-basics:
-
-=======================================
-How to write an I/O register controller
-=======================================
-
-The basics
-----------
-
-.. todo:: document IORegister controller howto
-
-.. _ALBA: http://www.cells.es/
-.. _ANKA: http://http://ankaweb.fzk.de/
-.. _ELETTRA: http://http://www.elettra.trieste.it/
-.. _ESRF: http://www.esrf.eu/
-.. _FRMII: http://www.frm2.tum.de/en/index.html
-.. _HASYLAB: http://hasylab.desy.de/
-.. _MAX-lab: http://www.maxlab.lu.se/maxlab/max4/index.html
-.. _SOLEIL: http://www.synchrotron-soleil.fr/
-
-.. _Tango: http://www.tango-controls.org/
-.. _Taco: http://www.esrf.eu/Infrastructure/Computing/TACO/
-.. _PyTango: http://packages.python.org/PyTango/
-.. _Taurus: http://packages.python.org/taurus/
-.. _QTango: http://www.tango-controls.org/download/index_html#qtango3
-.. _Qt: http://qt.nokia.com/products/
-.. _PyQt: http://www.riverbankcomputing.co.uk/software/pyqt/
-.. _PyQwt: http://pyqwt.sourceforge.net/
-.. _Python: http://www.python.org/
-.. _IPython: http://ipython.org/
-.. _ATK: http://www.tango-controls.org/Documents/gui/atk/tango-application-toolkit
-.. _Qub: http://www.blissgarden.org/projects/qub/
-.. _numpy: http://numpy.scipy.org/
-.. _SPEC: http://www.certif.com/
-.. _EPICS: http://www.aps.anl.gov/epics/
diff --git a/doc/source/devel/howto_controllers/howto_motorcontroller.rst b/doc/source/devel/howto_controllers/howto_motorcontroller.rst
deleted file mode 100644
index bb2aa272..00000000
--- a/doc/source/devel/howto_controllers/howto_motorcontroller.rst
+++ /dev/null
@@ -1,694 +0,0 @@
-.. currentmodule:: sardana.pool.controller
-
-.. _sardana-motorcontroller-howto-basics:
-
-===============================
-How to write a motor controller
-===============================
-
-The basics
-----------
-
-An example of a hypothetical *Springfield* motor controller will be build
-incrementally from scratch to aid in the explanation.
-
-By now you should have read the general controller basics chapter. You should
-now have a MotorController with a proper constructor, add and delete axis methods:
-
-.. code-block:: python
-
- import springfieldlib
-
- from sardana.pool.controller import MotorController
-
- class SpringfieldMotorController(MotorController):
-
- def __init__(self, inst, props, *args, **kwargs):
- super(SpringfieldMotorController, self).__init__(inst, props, *args, **kwargs)
-
- # initialize hardware communication
- self.springfield = springfieldlib.SpringfieldMotorHW()
-
- # do some initialization
- self._motors = {}
-
- def AddDevice(self, axis):
- self._motors[axis] = True
-
- def DeleteDevice(self, axis):
- del self._motor[axis]
-
-The *get axis state* method has some details that will be explained below.
-
-The examples use a :mod:`springfieldlib` module which emulates a motor hardware
-access library.
-
-The :mod:`springfieldlib` can be downloaded from
-:download:`here <springfieldlib.py>`.
-
-The Springfield motor controller can be downloaded from
-:download:`here <sf_motor_ctrl.py>`.
-
-The following code describes a minimal *Springfield* base motor controller
-which is able to return both the state and position of a motor as well as move
-a motor to the desired position:
-
-.. literalinclude:: sf_motor_ctrl.py
- :pyobject: SpringfieldBaseMotorController
-
-This code is shown only to demonstrate the minimal controller :term:`API`.
-The advanced motor controller chapters describe how to account for more complex
-behaviour like reducing the number of hardware accesses or synchronize motion of
-multiple motors.
-
-.. _sardana-motorcontroller-howto-axis-state:
-
-Get motor state
-~~~~~~~~~~~~~~~
-
-To get the state of a motor, sardana calls the
-:meth:`~sardana.pool.controller.Controller.StateOne` method. This method
-receives an axis as parameter and should return a sequence of three values:
-
-To get the state of a motor, sardana calls the
-:meth:`~sardana.pool.controller.Controller.StateOne` method. This method
-receives an axis as parameter and should return either:
-
- - state (:obj:`~sardana.sardanadefs.State`) or
- - a sequence of two elements:
- - state (:obj:`~sardana.sardanadefs.State`)
- - status (:obj:`str`) *or* limit switches (:obj:`int`)
- - a sequence of three elements:
- - state (:obj:`~sardana.sardanadefs.State`)
- - status (:obj:`str`)
- - limit switches (:obj:`int`)
-
-The state should be a member of :obj:`~sardana.sardanadefs.State` (For backward
-compatibility reasons, it is also supported to return one of
-:class:`PyTango.DevState`). The status could be any string. The limit switches
-is a integer with bits representing the three possible limits: home, upper
-and lower. Sardana provides three constants which can be *or*\ed together to
-provide the desired limit switch:
-
-.. hlist::
- :columns: 4
-
- - :attr:`~MotorController.NoLimitSwitch`
- - :attr:`~MotorController.HomeLimitSwitch`
- - :attr:`~MotorController.UpperLimitSwitch`
- - :attr:`~MotorController.LowerLimitSwitch`
-
-To say both home and lower limit switches are active (rare!) you can do::
-
- limit_switches = MotorController.HomeLimitSwitch | MotorController.LowerLimitSwitch
-
-If you don't return a status, sardana will compose a status string with:
-
- <axis name> is in <state name>
-
-If you don't return limit switches, sardana will assume all limit switches are
-off.
-
-Here is an example of the possible implementation of
-:meth:`~sardana.pool.controller.Controller.StateOne`:
-
-.. code-block:: python
- :emphasize-lines: 11
-
- from sardana import State
-
- class SpringfieldMotorController(MotorController):
-
- StateMap = {
- 1 : State.On,
- 2 : State.Moving,
- 3 : State.Fault,
- }
-
- def StateOne(self, axis):
- springfield = self.springfield
- state = self.StateMap[ springfield.getState(axis) ]
- status = springfield.getStatus(axis)
-
- limit_switches = MotorController.NoLimitSwitch
- hw_limit_switches = springfield.getLimits(axis)
- if hw_limit_switches[0]:
- limit_switches |= MotorController.HomeLimitSwitch
- if hw_limit_switches[1]:
- limit_switches |= MotorController.UpperLimitSwitch
- if hw_limit_switches[2]:
- limit_switches |= MotorController.LowerLimitSwitch
- return state, status, limit_switches
-
-.. _sardana-motorcontroller-howto-value:
-
-Get motor position
-~~~~~~~~~~~~~~~~~~
-
-To get the motor position, sardana calls the
-:meth:`~sardana.pool.controller.Readable.ReadOne` method. This method
-receives an axis as parameter and should return a valid position. Sardana
-interprets the returned position as a :term:`dial position`.
-
-Here is an example of the possible implementation of
-:meth:`~sardana.pool.controller.Readable.ReadOne`:
-
-.. code-block:: python
- :emphasize-lines: 3
-
- class SpringfieldMotorController(MotorController):
-
- def ReadOne(self, axis):
- position = self.springfield.getPosition(axis)
- return position
-
-.. _sardana-motorcontroller-howto-move:
-
-Move a motor
-~~~~~~~~~~~~
-
-When an order comes for sardana to move a motor, sardana will call the
-:meth:`~sardana.pool.controller.Startable.StartOne` method. This method receives
-an axis and a position. The controller code should trigger the hardware motion.
-The given position is always the :term:`dial position`.
-
-Here is an example of the possible implementation of
-:meth:`~sardana.pool.controller.Startable.StartOne`:
-
-.. code-block:: python
- :emphasize-lines: 3
-
- class SpringfieldMotorController(MotorController):
-
- def StartOne(self, axis, position):
- self.springfield.move(axis, position)
-
-As soon as :meth:`~sardana.pool.controller.Startable.StartOne` is invoked,
-sardana expects the motor to be moving. It enters a high frequency motion
-loop which asks for the motor state through calls to
-:meth:`~sardana.pool.controller.Controller.StateOne`. It will keep the loop
-running as long as the controller responds with ``State.Moving``.
-If :meth:`~sardana.pool.controller.Controller.StateOne` raises an exception
-or returns something other than ``State.Moving``, sardana will assume the motor
-is stopped and exit the motion loop.
-
-For a motion to work properly, it is therefore, **very important** that
-:meth:`~sardana.pool.controller.Controller.StateOne` responds correctly.
-
-.. _sardana-motorcontroller-howto-stop:
-
-Stop a motor
-~~~~~~~~~~~~
-
-It is possible to stop a motor when it is moving. When sardana is ordered to
-stop a motor motion, it invokes the :meth:`~sardana.pool.controller.Stopable.StopOne`
-method. This method receives an axis parameter. The controller should make
-sure the desired motor is *gracefully* stopped, if possible, respecting the
-configured motion parameters (like deceleration and base_rate).
-
-Here is an example of the possible implementation of
-:meth:`~sardana.pool.controller.Stopable.StopOne`:
-
-.. code-block:: python
- :emphasize-lines: 3
-
- class SpringfieldMotorController(MotorController):
-
- def StopOne(self, axis):
- self.springfield.stop(axis)
-
-.. _sardana-motorcontroller-howto-abort:
-
-Abort a motor
-~~~~~~~~~~~~~
-
-In a danger situation (motor moving a table about to hit a wall), it is
-desirable to abort a motion *as fast as possible*. When sardana is ordered to
-abort a motor motion, it invokes the :meth:`~sardana.pool.controller.Stopable.AbortOne`
-method. This method receives an axis parameter. The controller should make
-sure the desired motor is stopped as fast as it can be done, possibly losing
-track of position.
-
-Here is an example of the possible implementation of
-:meth:`~sardana.pool.controller.Stopable.AbortOne`:
-
-.. code-block:: python
- :emphasize-lines: 3
-
- class SpringfieldMotorController(MotorController):
-
- def AbortOne(self, axis):
- self.springfield.abort(axis)
-
-.. note::
-
- The default implementation of :meth:`~sardana.pool.controller.Stopable.StopOne`
- calls :meth:`~sardana.pool.controller.Stopable.AbortOne` so, if your
- controller cannot distinguish stopping from aborting, it is sufficient
- to implement :meth:`~sardana.pool.controller.Stopable.AbortOne`.
-
-.. _sardana-motorcontroller-howto-standard-axis-attributes:
-
-Standard axis attributes
-~~~~~~~~~~~~~~~~~~~~~~~~
-
-By default, sardana expects every axis to have a set of attributes:
-
-- acceleration
-- deceleration
-- velocity
-- base rate
-- steps per unit
-
-To set and retrieve the value of these attributes, sardana invokes pair of
-methods: :meth:`~sardana.pool.controller.Controller.GetAxisPar`
-/:meth:`~sardana.pool.controller.Controller.SetAxisPar`
-
-Here is an example of the possible implementation:
-
-.. code-block:: python
- :emphasize-lines: 3, 18
-
- class SpringfieldMotorController(MotorController):
-
- def GetAxisPar(self, axis, name):
- springfield = self.springfield
- name = name.lower()
- if name == "acceleration":
- v = springfield.getAccelerationTime(axis)
- elif name == "deceleration":
- v = springfield.getDecelerationTime(axis)
- elif name == "base_rate":
- v = springfield.getMinVelocity(axis)
- elif name == "velocity":
- v = springfield.getMaxVelocity(axis)
- elif name == "step_per_unit":
- v = springfield.getStepPerUnit(axis)
- return v
-
- def SetAxisPar(self, axis, name, value):
- springfield = self.springfield
- name = name.lower()
- if name == "acceleration":
- springfield.setAccelerationTime(axis, value)
- elif name == "deceleration":
- springfield.setDecelerationTime(axis, value)
- elif name == "base_rate":
- springfield.setMinVelocity(axis, value)
- elif name == "velocity":
- springfield.setMaxVelocity(axis, value)
- elif name == "step_per_unit":
- springfield.setStepPerUnit(axis, value)
-
-.. seealso::
-
- :ref:`sardana-motorcontroller-what-to-do`
- What to do when your hardware motor controller doesn't support
- steps per unit
-
-.. _sardana-motorcontroller-define-position:
-
-Define a position
-~~~~~~~~~~~~~~~~~
-
-Sometimes it is useful to reset the current position to a certain value.
-Imagine you are writing a controller for a hardware controller which handles
-stepper motors. When the hardware is asked for a motor position it will
-probably answer some value from an internal register which is
-incremented/decremented each time the motor goes up/down a step. Probably this
-value as physical meaning so the usual procedure is to move the motor to a known
-position (home switch, for example) and once there, set a meaningful position to
-the current position. Some motor controllers support reseting the internal
-register to the desired value. If your motor controller can do this the
-implementation is as easy as writing the
-:meth:`~sardana.pool.controller.MotorController.DefinePosition` and call the
-proper code of your hardware library to do it:
-
-.. code-block:: python
-
- class SpringfieldMotorController(MotorController):
-
- def DefinePosition(self, axis, position):
- self.springfield.setCurrentPosition(axis, position)
-
-.. seealso::
-
- :ref:`sardana-motorcontroller-what-to-do`
-
- What to do when your hardware motor controller doesn't support
- defining the position
-
-.. _sardana-motorcontroller-what-to-do:
-
-What to do when...
-~~~~~~~~~~~~~~~~~~
-
-This chapter describes common difficult situations you may face when writing
-a motor controller in sardana, and possible solutions to solve them.
-
-*my controller doesn't support steps per unit*
- Many (probably, most) hardware motor controllers don't support steps per
- unit at the hardware level. This means that your sardana controller should
- be able to emulate steps per unit at the software level.
- This can be easily done, but it requires you to make some changes in your
- code.
-
- We will assume now that the Springfield motor controller doesn't support
- steps per unit feature. The first that needs to be done is to modify the
- :meth:`~sardana.pool.controller.Controller.AddDevice` method so it is able to
- to store the resulting conversion factor between the hardware read position
- and the position the should be returned (the *step_per_unit*).
- The :meth:`~sardana.pool.controller.Readable.ReadOne` also needs to be
- rewritten to make the proper calculation.
- Finally :meth:`~sardana.pool.controller.Controller.GetAxisPar` /
- :meth:`~sardana.pool.controller.Controller.SetAxisPar` methods need to
- be rewritten to properly get/set the step per unit value:
-
- .. code-block:: python
-
- class SpringfieldMotorController(MotorController):
-
- def AddDevice(self, axis):
- self._motor[axis] = dict(step_per_unit=1.0)
-
- def ReadOne(self, axis):
- step_per_unit = self._motor[axis]["step_per_unit"]
- position = self.springfield.getPosition(axis)
- return position / step_per_unit
-
- def GetAxisPar(self, axis, name):
- springfield = self.springfield
- name = name.lower()
- if name == "acceleration":
- v = springfield.getAccelerationTime(axis)
- elif name == "deceleration":
- v = springfield.getDecelerationTime(axis)
- elif name == "base_rate":
- v = springfield.getMinVelocity(axis)
- elif name == "velocity":
- v = springfield.getMaxVelocity(axis)
- elif name == "step_per_unit":
- v = self._motor[axis]["step_per_unit"]
- return v
-
- def SetAxisPar(self, axis, name, value):
- springfield = self.springfield
- name = name.lower()
- if name == "acceleration":
- springfield.setAccelerationTime(axis, value)
- elif name == "deceleration":
- springfield.setDecelerationTime(axis, value)
- elif name == "base_rate":
- springfield.setMinVelocity(axis, value)
- elif name == "velocity":
- springfield.setMaxVelocity(axis, value)
- elif name == "step_per_unit":
- self._motor[axis]["step_per_unit"] = value
-
-*my controller doesn't support defining the position*
- Some controllers may not be able to reset the position to a different value.
- In these cases, your controller code should be able to emulate such a
- feature. This can be easily done, but it requires you to make some changes
- in your code.
-
- We will now assume that the Springfield motor controller doesn't support
- steps per unit feature. The first thing that needs to be done is to modify the
- :meth:`~sardana.pool.controller.Controller.AddDevice` method so it is able
- to store the resulting offset between the hardware read position and the
- position the should be returned (the *define_position_offset*).
- The :meth:`~sardana.pool.controller.Readable.ReadOne` also needs to be
- rewritten to take the *define_position_offset* into account.
- Finally :meth:`~sardana.pool.controller.MotorController.DefinePosition`
- needs to be written to update the *define_position_offset* to the desired
- value:
-
- .. code-block:: python
-
- class SpringfieldMotorController(MotorController):
-
- def AddDevice(self, axis):
- self._motor[axis] = dict(define_position_offset=0.0)
-
- def ReadOne(self, axis):
- dp_offset = self._motor[axis]["define_position_offset"]
- position = self.springfield.getPosition(axis)
- return position + dp_offset
-
- def DefinePosition(self, axis, position):
- current_position = self.springfield.getPosition(axis)
- self._motor[axis]["define_position_offset"] = position - current_position
-
-
-Advanced topics
----------------
-
-.. _sardana-motorcontroller-howto-timestamp-position:
-
-Timestamp a motor position
-~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-When you read the position of a motor from the hardware sometimes it is
-necessary to associate a timestamp with that position so you can track the
-position of a motor in time.
-
-If sardana is executed as a Tango device server, reading the position
-attribute from the motor device triggers the execution of your controller's
-:meth:`~sardana.pool.controller.Readable.ReadOne` method. Tango responds with
-the value your controller returns from the call to
-:meth:`~sardana.pool.controller.Readable.ReadOne` and automatically assigns
-a timestamp. However this timestamp has a certain delay since the time the
-value was actually read from hardware and the time Tango generates the timestamp.
-
-To avoid this, sardana supports returning in
-:meth:`~sardana.pool.controller.Readable.ReadOne` an object that contains both
-the value and the timestamp instead of the usual :class:`numbers.Number`.
-The object must be an instance of :class:`~sardana.sardanavalue.SardanaValue`.
-
-Here is an example of associating a timestamp in
-:meth:`~sardana.pool.controller.Readable.ReadOne`:
-
-.. code-block:: python
-
- import time
- from sardana.pool.controller import SardanaValue
-
- class SpringfieldMotorController(MotorController):
-
- def ReadOne(self, axis):
- return SardanaValue(value=self.springfield.getPosition(axis),
- timestamp=time.time())
-
-If your controller communicates with a Tango device, Sardana also supports
-returning a :class:`~PyTango.DeviceAttribute` object. Sardana will use this
-object's value and timestamp. Example:
-
-.. code-block:: python
-
- class TangoMotorController(MotorController):
-
- def ReadOne(self, axis):
- return self.device.read_attribute("position")
-
-.. _sardana-motorcontroller-howto-mutiple-motion:
-
-Multiple motion synchronization
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-This chapter describes an extended :term:`API` that allows you to better
-synchronize motions involing more than one motor, as well as optimize
-hardware communication (in case the hardware interface also supports this).
-
-Often it is the case that the experiment/procedure the user runs requires to
-move more than one motor at the same time.
-Imagine that the user requires motor at axis 1 to be moved to 100mm and motor
-axis 2 to be moved to -20mm.
-Your controller will receive two consecutive calls to
-:meth:`~sardana.pool.controller.Startable.StartOne`:
-
-.. code-block:: python
-
- StartOne(1, 100)
- StartOne(2, -20)
-
-and each StartOne will probably connect to the hardware (through serial line,
-socket, Tango_ or EPICS_) and ask the motor to be moved.
-This will do the job but, there will be a slight desynchronization between the
-two motors because hardware call of motor 1 will be done before hardware call
-to motor 2.
-
-Sardana provides an extended *start motion* which gives you the possibility
-to improve the syncronization (and probably reduce communications) but your
-hardware controller must somehow support this feature as well.
-
-The complete start motion :term:`API` consists of four methods:
-
- - :meth:`~sardana.pool.controller.Startable.PreStartAll`
- - :meth:`~sardana.pool.controller.Startable.PreStartOne`
- - :meth:`~sardana.pool.controller.Startable.StartOne`
- - :meth:`~sardana.pool.controller.Startable.StartAll`
-
-Except for :meth:`~sardana.pool.controller.Startable.StartOne`, the
-implemenation of all other start methods is optional and their default
-implementation does nothing (:meth:`~sardana.pool.controller.Startable.PreStartOne`
-actually returns ``True``).
-
-So, actually, the complete algorithm for motor motion in sardana is::
-
- /FOR/ Each controller(s) implied in the motion
- - Call PreStartAll()
- /END FOR/
-
- /FOR/ Each motor(s) implied in the motion
- - ret = PreStartOne(motor to move, new position)
- - /IF/ ret is not true
- /RAISE/ Cannot start. Motor PreStartOne returns False
- - /END IF/
- - Call StartOne(motor to move, new position)
- /END FOR/
-
- /FOR/ Each controller(s) implied in the motion
- - Call StartAll()
- /END FOR/
-
-So, for the example above where we move two motors, the complete sequence of
-calls to the controller is:
-
-.. code-block:: python
-
- PreStartAll()
-
- if not PreStartOne(1, 100):
- raise Exception("Cannot start. Motor(1) PreStartOne returns False")
- if not PreStartOne(2, -20):
- raise Exception("Cannot start. Motor(2) PreStartOne returns False")
-
- StartOne(1, 100)
- StartOne(2, -20)
-
- StartAll()
-
-Sardana assures that the above sequence is never interrupted by other calls,
-like a call from a different user to get motor state.
-
-Suppose the springfield library tells us in the documentation that:
-
- ... to move multiple motors at the same time use::
-
- moveMultiple(seq<pair<axis, position>>)
-
- Example::
-
- moveMultiple([[1, 100], [2, -20]])
-
-We can modify our motor controller to take profit of this hardware feature:
-
-.. code-block:: python
-
- class SpringfieldMotorController(MotorController):
-
- def PreStartAll(self):
- # clear the local motion information dictionary
- self._moveable_info = []
-
- def StartOne(self, axis, position):
- # store information about this axis motion
- motion_info = axis, position
- self._moveable_info.append(motion_info)
-
- def StartAll(self):
- self.springfield.moveMultiple(self._moveable_info)
-
-A similar principle applies when sardana asks for the state and position of
-multiple axis. The two sets of methods are, in these cases:
-
-.. hlist::
- :columns: 2
-
- - :meth:`~sardana.pool.controller.Controller.PreStateAll`
- - :meth:`~sardana.pool.controller.Controller.PreStateOne`
- - :meth:`~sardana.pool.controller.Controller.StateAll`
- - :meth:`~sardana.pool.controller.Controller.StateOne`
- - :meth:`~sardana.pool.controller.Readable.PreReadAll`
- - :meth:`~sardana.pool.controller.Readable.PreReadOne`
- - :meth:`~sardana.pool.controller.Readable.ReadAll`
- - :meth:`~sardana.pool.controller.Readable.ReadOne`
-
-The main differences between these sets of methods and the ones from start motion
-is that :meth:`~sardana.pool.controller.Controller.StateOne` /
-:meth:`~sardana.pool.controller.Readable.ReadOne` methods are called **AFTER**
-the corresponding :meth:`~sardana.pool.controller.Controller.StateAll` /
-:meth:`~sardana.pool.controller.Readable.ReadAll` counterparts and they are
-expeced to return the state/position of the requested axis.
-
-The internal sardana algorithm to read position is::
-
- /FOR/ Each controller(s) implied in the reading
- - Call PreReadAll()
- /END FOR/
-
- /FOR/ Each motor(s) implied in the reading
- - PreReadOne(motor to read)
- /END FOR/
-
- /FOR/ Each controller(s) implied in the reading
- - Call ReadAll()
- /END FOR/
-
- /FOR/ Each motor(s) implied in the reading
- - Call ReadOne(motor to read)
- /END FOR/
-
-Here is an example assuming the springfield library tells us in the
-documentation that:
-
- ... to read the position of multiple motors at the same time use::
-
- getMultiplePosition(seq<axis>) -> dict<axis, position>
-
- Example::
-
- positions = getMultiplePosition([1, 2])
-
-The new improved code could look like this::
-
- class SpringfieldMotorController(MotorController):
-
- def PreRealAll(self):
- # clear the local position information dictionary
- self._position_info = []
-
- def PreReadOne(self, axis):
- self._position_info.append(axis)
-
- def ReadAll(self):
- self._positions = self.springfield.getMultiplePosition(self._position_info)
-
- def ReadOne(self, axis):
- return self._positions[axis]
-
-
-.. _ALBA: http://www.cells.es/
-.. _ANKA: http://http://ankaweb.fzk.de/
-.. _ELETTRA: http://http://www.elettra.trieste.it/
-.. _ESRF: http://www.esrf.eu/
-.. _FRMII: http://www.frm2.tum.de/en/index.html
-.. _HASYLAB: http://hasylab.desy.de/
-.. _MAX-lab: http://www.maxlab.lu.se/maxlab/max4/index.html
-.. _SOLEIL: http://www.synchrotron-soleil.fr/
-
-.. _Tango: http://www.tango-controls.org/
-.. _Taco: http://www.esrf.eu/Infrastructure/Computing/TACO/
-.. _PyTango: http://packages.python.org/PyTango/
-.. _Taurus: http://packages.python.org/taurus/
-.. _QTango: http://www.tango-controls.org/download/index_html#qtango3
-.. _Qt: http://qt.nokia.com/products/
-.. _PyQt: http://www.riverbankcomputing.co.uk/software/pyqt/
-.. _PyQwt: http://pyqwt.sourceforge.net/
-.. _Python: http://www.python.org/
-.. _IPython: http://ipython.org/
-.. _ATK: http://www.tango-controls.org/Documents/gui/atk/tango-application-toolkit
-.. _Qub: http://www.blissgarden.org/projects/qub/
-.. _numpy: http://numpy.scipy.org/
-.. _SPEC: http://www.certif.com/
-.. _EPICS: http://www.aps.anl.gov/epics/
- \ No newline at end of file
diff --git a/doc/source/devel/howto_controllers/howto_pseudocountercontroller.rst b/doc/source/devel/howto_controllers/howto_pseudocountercontroller.rst
deleted file mode 100644
index 91ef8d7e..00000000
--- a/doc/source/devel/howto_controllers/howto_pseudocountercontroller.rst
+++ /dev/null
@@ -1,37 +0,0 @@
-.. currentmodule:: sardana.pool.controller
-
-.. _sardana-pseudocountercontroller-howto-basics:
-
-========================================
-How to write a pseudo counter controller
-========================================
-
-The basics
-----------
-
-.. todo:: document pseudo counter controller howto
-
-.. _ALBA: http://www.cells.es/
-.. _ANKA: http://http://ankaweb.fzk.de/
-.. _ELETTRA: http://http://www.elettra.trieste.it/
-.. _ESRF: http://www.esrf.eu/
-.. _FRMII: http://www.frm2.tum.de/en/index.html
-.. _HASYLAB: http://hasylab.desy.de/
-.. _MAX-lab: http://www.maxlab.lu.se/maxlab/max4/index.html
-.. _SOLEIL: http://www.synchrotron-soleil.fr/
-
-.. _Tango: http://www.tango-controls.org/
-.. _Taco: http://www.esrf.eu/Infrastructure/Computing/TACO/
-.. _PyTango: http://packages.python.org/PyTango/
-.. _Taurus: http://packages.python.org/taurus/
-.. _QTango: http://www.tango-controls.org/download/index_html#qtango3
-.. _Qt: http://qt.nokia.com/products/
-.. _PyQt: http://www.riverbankcomputing.co.uk/software/pyqt/
-.. _PyQwt: http://pyqwt.sourceforge.net/
-.. _Python: http://www.python.org/
-.. _IPython: http://ipython.org/
-.. _ATK: http://www.tango-controls.org/Documents/gui/atk/tango-application-toolkit
-.. _Qub: http://www.blissgarden.org/projects/qub/
-.. _numpy: http://numpy.scipy.org/
-.. _SPEC: http://www.certif.com/
-.. _EPICS: http://www.aps.anl.gov/epics/
diff --git a/doc/source/devel/howto_controllers/howto_pseudomotorcontroller.rst b/doc/source/devel/howto_controllers/howto_pseudomotorcontroller.rst
deleted file mode 100644
index b3a1a841..00000000
--- a/doc/source/devel/howto_controllers/howto_pseudomotorcontroller.rst
+++ /dev/null
@@ -1,37 +0,0 @@
-.. currentmodule:: sardana.pool.controller
-
-.. _sardana-pseudomotorcontroller-howto-basics:
-
-======================================
-How to write a pseudo motor controller
-======================================
-
-The basics
-----------
-
-.. todo:: document pseudo motor controller howto
-
-.. _ALBA: http://www.cells.es/
-.. _ANKA: http://http://ankaweb.fzk.de/
-.. _ELETTRA: http://http://www.elettra.trieste.it/
-.. _ESRF: http://www.esrf.eu/
-.. _FRMII: http://www.frm2.tum.de/en/index.html
-.. _HASYLAB: http://hasylab.desy.de/
-.. _MAX-lab: http://www.maxlab.lu.se/maxlab/max4/index.html
-.. _SOLEIL: http://www.synchrotron-soleil.fr/
-
-.. _Tango: http://www.tango-controls.org/
-.. _Taco: http://www.esrf.eu/Infrastructure/Computing/TACO/
-.. _PyTango: http://packages.python.org/PyTango/
-.. _Taurus: http://packages.python.org/taurus/
-.. _QTango: http://www.tango-controls.org/download/index_html#qtango3
-.. _Qt: http://qt.nokia.com/products/
-.. _PyQt: http://www.riverbankcomputing.co.uk/software/pyqt/
-.. _PyQwt: http://pyqwt.sourceforge.net/
-.. _Python: http://www.python.org/
-.. _IPython: http://ipython.org/
-.. _ATK: http://www.tango-controls.org/Documents/gui/atk/tango-application-toolkit
-.. _Qub: http://www.blissgarden.org/projects/qub/
-.. _numpy: http://numpy.scipy.org/
-.. _SPEC: http://www.certif.com/
-.. _EPICS: http://www.aps.anl.gov/epics/
diff --git a/doc/source/devel/howto_controllers/index.rst b/doc/source/devel/howto_controllers/index.rst
deleted file mode 100644
index 964f332d..00000000
--- a/doc/source/devel/howto_controllers/index.rst
+++ /dev/null
@@ -1,32 +0,0 @@
-.. currentmodule:: sardana.pool.controller
-
-.. _sardana-controller-howto:
-
-===================
-Writing controllers
-===================
-
-This chapter provides the necessary information to write controllers in sardana.
-
-An overview of the pool controller concept can be found
-:ref:`here <sardana-controller-overview>`.
-
-The complete controller :term:`API` can be found
-:ref:`here <sardana-controller-api>`.
-
-First, the common interface to all controller types is explained. After, a
-detailed chapter will focus on each specific controller type:
-
-.. toctree::
- :maxdepth: 1
-
- howto_controller
- howto_motorcontroller
- howto_countertimercontroller
- howto_0dcontroller
- howto_1dcontroller
- howto_2dcontroller
- howto_ioregistercontroller
- howto_pseudomotorcontroller
- howto_pseudocountercontroller
-
diff --git a/doc/source/devel/howto_controllers/sf_ct_ctrl.py b/doc/source/devel/howto_controllers/sf_ct_ctrl.py
deleted file mode 100644
index 4da7c50a..00000000
--- a/doc/source/devel/howto_controllers/sf_ct_ctrl.py
+++ /dev/null
@@ -1,122 +0,0 @@
-##############################################################################
-##
-## This file is part of Sardana
-##
-## http://www.sardana-controls.org/
-##
-## Copyright 2011 CELLS / ALBA Synchrotron, Bellaterra, Spain
-##
-## Sardana is free software: you can redistribute it and/or modify
-## it under the terms of the GNU Lesser General Public License as published by
-## the Free Software Foundation, either version 3 of the License, or
-## (at your option) any later version.
-##
-## Sardana is distributed in the hope that it will be useful,
-## but WITHOUT ANY WARRANTY; without even the implied warranty of
-## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-## GNU Lesser General Public License for more details.
-##
-## You should have received a copy of the GNU Lesser General Public License
-## along with Sardana. If not, see <http://www.gnu.org/licenses/>.
-##
-##############################################################################
-
-"""This file contains the code for an hypothetical Springfield counter/timer
-controller used in documentation"""
-
-import time
-
-import springfieldlib
-
-from sardana import State
-from sardana.pool.controller import CounterTimerController
-
-class SpringfieldBaseCounterTimerController(CounterTimerController):
- """The most basic controller intended from demonstration purposes only.
- This is the absolute minimum you have to implement to set a proper counter
- controller able to get a counter value, get a counter state and do an
- acquisition.
-
- This example is so basic that it is not even directly described in the
- documentation"""
-
- def __init__(self, inst, props, *args, **kwargs):
- """Constructor"""
- super(SpringfieldBaseCounterTimerController, self).__init__(inst, props, *args, **kwargs)
- self.springfield = springfieldlib.SpringfieldCounterHW()
-
- def ReadOne(self, axis):
- """Get the specified counter value"""
- return self.springfield.getValue(axis)
-
- def StateOne(self, axis):
- """Get the specified counter state"""
- springfield = self.springfield
- state = springfield.getState(axis)
- if state == 1:
- return State.On, "Counter is stopped"
- elif state == 2:
- return State.Moving, "Counter is acquiring"
- elif state == 3:
- return State.Fault, "Counter has an error"
-
- def StartAll(self):
- self.springfield.start_count()
-
- def StartOne(self, axis, value=None):
- """acquire the specified counter"""
- self.springfield.activate_channel(axis)
-
- def LoadOne(self, axis, value):
- self.springfield.set_master(axis, value)
-
- def StopOne(self, axis):
- """Stop the specified counter"""
- self.springfield.stop(axis)
-
-
-from sardana import DataAccess
-from sardana.pool.controller import Type, Description, DefaultValue, Access, FGet, FSet
-
-class SpringfieldCounterTimerController(CounterTimerController):
-
- def __init__(self, inst, props, *args, **kwargs):
- super(SpringfieldCounterTimerController, self).__init__(inst, props, *args, **kwargs)
-
- # initialize hardware communication
- self.springfield = springfieldlib.SpringfieldCounterHW()
-
- # do some initialization
- self._counters = {}
-
- def AddDevice(self, axis):
- self._counters[axis] = True
-
- def DeleteDevice(self, axis):
- del self._counters[axis]
-
- StateMap = {
- 1 : State.On,
- 2 : State.Moving,
- 3 : State.Fault,
- }
-
- def StateOne(self, axis):
- springfield = self.springfield
- state = self.StateMap[ springfield.getState(axis) ]
- status = springfield.getStatus(axis)
- return state, status
-
- def ReadOne(self, axis):
- value = self.springfield.getValue(axis)
- return value
-
- def StartOne(self, axis, position):
- self.springfield.move(axis, position)
-
- def StopOne(self, axis):
- self.springfield.stop(axis)
-
- def AbortOne(self, axis):
- self.springfield.abort(axis)
- \ No newline at end of file
diff --git a/doc/source/devel/howto_controllers/sf_motor_ctrl.py b/doc/source/devel/howto_controllers/sf_motor_ctrl.py
deleted file mode 100644
index 80d938bb..00000000
--- a/doc/source/devel/howto_controllers/sf_motor_ctrl.py
+++ /dev/null
@@ -1,141 +0,0 @@
-##############################################################################
-##
-## This file is part of Sardana
-##
-## http://www.sardana-controls.org/
-##
-## Copyright 2011 CELLS / ALBA Synchrotron, Bellaterra, Spain
-##
-## Sardana is free software: you can redistribute it and/or modify
-## it under the terms of the GNU Lesser General Public License as published by
-## the Free Software Foundation, either version 3 of the License, or
-## (at your option) any later version.
-##
-## Sardana is distributed in the hope that it will be useful,
-## but WITHOUT ANY WARRANTY; without even the implied warranty of
-## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-## GNU Lesser General Public License for more details.
-##
-## You should have received a copy of the GNU Lesser General Public License
-## along with Sardana. If not, see <http://www.gnu.org/licenses/>.
-##
-##############################################################################
-
-"""This file contains the code for an hypothetical Springfield motor controller
-used in documentation"""
-
-import springfieldlib
-
-from sardana import State
-from sardana.pool.controller import MotorController
-
-class SpringfieldBaseMotorController(MotorController):
- """The most basic controller intended from demonstration purposes only.
- This is the absolute minimum you have to implement to set a proper motor
- controller able to get a motor position, get a motor state and move a
- motor.
-
- This example is so basic that it is not even directly described in the
- documentation"""
-
- MaxDevice = 128
-
- def __init__(self, inst, props, *args, **kwargs):
- """Constructor"""
- super(SpringfieldBaseMotorController, self).__init__(inst, props, *args, **kwargs)
- self.springfield = springfieldlib.SpringfieldMotorHW()
-
- def ReadOne(self, axis):
- """Get the specified motor position"""
- return self.springfield.getPosition(axis)
-
- def StateOne(self, axis):
- """Get the specified motor state"""
- springfield = self.springfield
- state = springfield.getState(axis)
- if state == 1:
- return State.On, "Motor is stopped"
- elif state == 2:
- return State.Moving, "Motor is moving"
- elif state == 3:
- return State.Fault, "Motor has an error"
-
- def StartOne(self, axis, position):
- """Move the specified motor to the specified position"""
- self.springfield.move(axis, position)
-
- def StopOne(self, axis):
- """Stop the specified motor"""
- self.springfield.stop(axis)
-
-
-from sardana import DataAccess
-from sardana.pool.controller import Type, Description, DefaultValue, Access, FGet, FSet
-
-class SpringfieldMotorController(MotorController):
-
- axis_attributes = {
- "CloseLoop" : {
- Type : bool,
- Description : "(de)activates the motor close loop algorithm",
- DefaultValue : False,
- },
- }
-
- def getCloseLoop(self, axis):
- return self.springfield.isCloseLoopActive(axis)
-
- def setCloseLoop(self, axis, value):
- self.springfield.setCloseLoop(axis, value)
-
- def __init__(self, inst, props, *args, **kwargs):
- super(SpringfieldMotorController, self).__init__(inst, props, *args, **kwargs)
-
- # initialize hardware communication
- self.springfield = springfieldlib.SpringfieldMotorHW()
-
- # do some initialization
- self._motors = {}
-
- def AddDevice(self, axis):
- self._motors[axis] = True
-
- def DeleteDevice(self, axis):
- del self._motors[axis]
-
- StateMap = {
- 1 : State.On,
- 2 : State.Moving,
- 3 : State.Fault,
- }
-
- def StateOne(self, axis):
- springfield = self.springfield
- state = self.StateMap[ springfield.getState(axis) ]
- status = springfield.getStatus(axis)
-
- limit_switches = MotorController.NoLimitSwitch
- hw_limit_switches = springfield.getLimits(axis)
- if hw_limit_switches[0]:
- limit_switches |= MotorController.HomeLimitSwitch
- if hw_limit_switches[1]:
- limit_switches |= MotorController.UpperLimitSwitch
- if hw_limit_switches[2]:
- limit_switches |= MotorController.LowerLimitSwitch
- return state, status, limit_switches
-
- def ReadOne(self, axis):
- position = self.springfield.getPosition(axis)
- return position
-
- def StartOne(self, axis, position):
- self.springfield.move(axis, position)
-
- def StopOne(self, axis):
- self.springfield.stop(axis)
-
- def AbortOne(self, axis):
- self.springfield.abort(axis)
-
- def DefinePosition(self, axis, position):
- self.springfield.setCurrentPosition(axis, position)
diff --git a/doc/source/devel/howto_controllers/springfieldlib.py b/doc/source/devel/howto_controllers/springfieldlib.py
deleted file mode 100644
index f141ffee..00000000
--- a/doc/source/devel/howto_controllers/springfieldlib.py
+++ /dev/null
@@ -1,653 +0,0 @@
-##############################################################################
-##
-## This file is part of Sardana
-##
-## http://www.sardana-controls.org/
-##
-## Copyright 2011 CELLS / ALBA Synchrotron, Bellaterra, Spain
-##
-## Sardana is free software: you can redistribute it and/or modify
-## it under the terms of the GNU Lesser General Public License as published by
-## the Free Software Foundation, either version 3 of the License, or
-## (at your option) any later version.
-##
-## Sardana is distributed in the hope that it will be useful,
-## but WITHOUT ANY WARRANTY; without even the implied warranty of
-## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-## GNU Lesser General Public License for more details.
-##
-## You should have received a copy of the GNU Lesser General Public License
-## along with Sardana. If not, see <http://www.gnu.org/licenses/>.
-##
-##############################################################################
-
-"""This file contains the code for an hypothetical Springfield motor hardware
-access library. It is intended to be used in the sardana documentation as
-an aid to writing a sardana motor controller library.
-
-If you intend to use this code please put it in a directory accessible to
-Python or in the same directory as sf_motor_ctrl.py"""
-
-__all__ = ["SpringfieldMotorHW", "SpringfieldCounterHW"]
-
-import time
-from math import pow, sqrt
-
-class BaseMotion(object):
-
- def __init__(self):
- self.min_vel = -1
- self.max_vel = -1
- self.accel_time = -1
- self.decel_time = -1
- self.accel = -1
- self.decel = -1
-
- self.init_pos = -1
- self.final_pos = -1
- self.curr_pos = -1
-
-
-class Motion(BaseMotion):
-
- def __init__(self):
- BaseMotion.__init__(self)
-
- self.close_loop = False
-
- self.dsplmnt_reach_max_vel = -1
- self.dsplmnt_reach_min_vel = -1
- self.dsplmnt = -1
-
- self.curr_instant = -1
- self.start_instant = -1
-
- self.positive_dsplmnt = True
- self.small_motion = False
-
- # position where maximum velocity will be reached
- self.curr_max_vel_pos = -1
-
- # necessary displacement to reach maximum velocity
- self.curr_dsplmnt_reach_max_vel = -1
-
- # necessary diplacement to reach minimum velocity
- self.curr_dsplmnt_reach_min_vel = -1
-
- # maximum velocity possible
- self.curr_max_vel = -1
-
- # time at maximum velocity
- self.curr_at_max_vel_dsplmnt = -1
-
- # time to reach maximum velocity
- self.curr_max_vel_time = -1
-
- # time to reach minimum velocity
- self.curr_min_vel_time = -1
-
- # time at maximum velocity
- self.curr_at_max_vel_time = -1
-
- # instant when maximum velocity should be reached
- self.curr_max_vel_instant = -1
-
- # instant when should start decelerating
- self.curr_min_vel_instant = -1
-
- # time the motion will take
- self.duration = -1
-
- # instant the motion will end
- self.final_instant = -1
-
- # steps per unit
- self.step_per_unit = 1
-
- self.inMotion = False
-
- self.lower_ls = float('-inf')
- self.upper_ls = float('+inf')
-
- self.power = True
- self.enabled = True
-
- self.__recalculate_acc_constants()
-
- def isCloseLoopActive(self):
- return self.close_loop
-
- def setCloseLoop(self, v):
- self.close_loop = v
-
- def setMinVelocity(self,vi):
- """ Sets the minimum velocity in ms^-1. A.k.a. base rate"""
- vi = float(vi)
- if vi < 0:
- raise "Minimum velocity must be >= 0"
-
- self.min_vel = vi
-
- if self.max_vel < self.min_vel:
- self.max_vel = self.min_vel
-
- # force recalculation of accelerations
- if self.accel_time >= 0:
- self.setAccelerationTime(self.accel_time)
- if self.decel_time >= 0:
- self.setDecelerationTime(self.decel_time)
-
- def getMinVelocity(self):
- return self.min_vel
-
- def setMaxVelocity(self,vf):
- """ Sets the maximum velocity in ms^-1."""
- vf = float(vf)
- if vf <= 0:
- raise "Maximum velocity must be > 0"
-
- self.max_vel = vf
-
- if self.min_vel > self.max_vel:
- self.min_vel = self.max_vel
-
- # force recalculation of accelerations
- if self.accel_time >= 0:
- self.setAccelerationTime(self.accel_time)
- if self.decel_time >= 0:
- self.setDecelerationTime(self.decel_time)
-
- def getMaxVelocity(self):
- return self.max_vel
-
- def setAccelerationTime(self,at):
- """Sets the time to go from minimum velocity to maximum velocity in seconds"""
- at = float(at)
- if at <= 0:
- raise "Acceleration time must be > 0"
-
- self.accel_time = at
- self.accel = (self.max_vel - self.min_vel) / at
-
- self.__recalculate_acc_constants()
-
- def getAccelerationTime(self):
- return self.accel_time
-
- def setDecelerationTime(self,dt):
- """Sets the time to go from maximum velocity to minimum velocity in seconds"""
- dt = float(dt)
- if dt <= 0:
- raise "Deceleration time must be > 0"
-
- self.decel_time = dt
- self.decel = (self.min_vel - self.max_vel) / dt
-
- self.__recalculate_acc_constants()
-
- def getDecelerationTime(self):
- return self.decel_time
-
- def setAcceleration(self,a):
- """Sets the acceleration in ms^-2"""
- a = float(a)
- if a < 0:
- raise "Acceleration must be >= 0"
-
- self.accel = float(a)
-
- if a > 0:
- self.accel_time = (self.max_vel - self.min_vel) / a
- else:
- self.accel_time = float('INF')
-
- self.__recalculate_acc_constants()
-
- def setDeceleration(self,d):
- """Sets the deceleration in ms^-2"""
- d = float(d)
- if d > 0:
- raise "Deceleration must be <= 0"
-
- self.decel = d
-
- if d < 0:
- self.decel_time = (self.min_vel - self.max_vel) / d
- else:
- self.decel_time = float('INF')
-
- self.__recalculate_acc_constants()
-
- def getStepPerUnit(self):
- return self.step_per_unit
-
- def setStepPerUnit(self, spu):
- self.step_per_unit = spu
-
- def __recalculate_acc_constants(self):
- """precomputations assuming maximum speed can be reached in a motion"""
-
- self.dsplmnt_reach_max_vel = 0.5 * self.accel * pow(self.accel_time,2)
- self.dsplmnt_reach_max_vel += self.min_vel * self.accel_time
-
- self.dsplmnt_reach_min_vel = 0.5 * self.decel * pow(self.decel_time,2)
- self.dsplmnt_reach_min_vel += self.max_vel * self.decel_time
-
- def startMotion(self, initial_user_pos, final_user_pos, start_instant=None):
- """starts a new motion"""
-
- if not self.power:
- raise Exception("Motor is powered off")
-
- initial_pos = initial_user_pos * self.step_per_unit
- final_pos = final_user_pos * self.step_per_unit
-
- if self.inMotion:
- raise Exception("Already in motion")
-
- if initial_pos == final_pos:
- return
-
- self.init_pos = initial_pos
- self.final_pos = final_pos
- self.curr_pos = initial_pos
- self.dsplmnt = abs(final_pos - initial_pos)
-
- start_instant = start_instant or time.time()
- self.curr_instant = start_instant
- self.start_instant = start_instant
-
- self.positive_dsplmnt = final_pos >= initial_pos
-
- displmnt_not_cnst = self.dsplmnt_reach_max_vel + self.dsplmnt_reach_min_vel
- self.small_motion = self.dsplmnt < displmnt_not_cnst
-
- if self.positive_dsplmnt:
- self.curr_accel = self.accel
- self.curr_decel = self.decel
- else:
- self.curr_accel = -self.accel
- self.curr_decel = -self.decel
-
-
- if not self.small_motion:
-
- # necessary displacement to reach maximum velocity
- self.curr_dsplmnt_reach_max_vel = self.dsplmnt_reach_max_vel
- # necessary diplacement to reach minimum velocity
- self.curr_dsplmnt_reach_min_vel = self.dsplmnt_reach_min_vel
-
- if self.positive_dsplmnt:
- self.curr_max_vel = self.max_vel
- self.curr_min_vel = self.min_vel
- # position where maximum velocity will be reached
- self.curr_max_vel_pos = self.init_pos + self.curr_dsplmnt_reach_max_vel
- else:
- self.curr_max_vel = -self.max_vel
- self.curr_min_vel = -self.min_vel
- # position where maximum velocity will be reached
- self.curr_max_vel_pos = self.init_pos - self.curr_dsplmnt_reach_max_vel
-
- # displacement at maximum velocity
- self.curr_at_max_vel_dsplmnt = self.dsplmnt - (self.curr_dsplmnt_reach_max_vel + self.curr_dsplmnt_reach_min_vel)
-
- else: # Small movement
- # position where maximum velocity will be reached
- self.curr_max_vel_pos = self.init_pos * self.curr_accel - self.final_pos * self.curr_decel
- self.curr_max_vel_pos /= self.curr_accel - self.curr_decel
-
- # necessary displacement to reach maximum velocity
- self.curr_dsplmnt_reach_max_vel = abs(self.curr_max_vel_pos - self.init_pos)
-
- # necessary diplacement to reach minimum velocity
- self.curr_dsplmnt_reach_min_vel = abs(self.final_pos - self.curr_max_vel_pos)
-
- # maximum velocity possible
- cnst = 2 * self.curr_accel * self.curr_decel * self.dsplmnt / (self.curr_decel - self.curr_accel)
- max_vel_2 = pow(self.min_vel, 2) + cnst
-
- self.curr_max_vel = sqrt(abs(max_vel_2))
-
- if self.positive_dsplmnt:
- self.curr_min_vel = self.min_vel
- else:
- self.curr_max_vel = -self.curr_max_vel
- self.curr_min_vel = -self.min_vel
-
- # displacement at maximum velocity
- self.curr_at_max_vel_dsplmnt = 0.0
-
- # time to reach maximum velocity
- self.curr_max_vel_time = abs((self.curr_max_vel - self.curr_min_vel) / self.curr_accel)
-
- # time to reach minimum velocity
- self.curr_min_vel_time = abs((self.curr_min_vel - self.curr_max_vel) / self.curr_decel)
-
- # time at maximum velocity
- self.curr_at_max_vel_time = abs(self.curr_at_max_vel_dsplmnt / self.curr_max_vel)
-
- # instant when maximum velocity should be reached
- self.curr_max_vel_instant = self.start_instant + self.curr_max_vel_time
-
- # instant when should start decelerating
- self.curr_min_vel_instant = self.curr_max_vel_instant + self.curr_at_max_vel_time
-
- # time the motion will take
- self.duration = self.curr_max_vel_time + self.curr_at_max_vel_time + self.curr_min_vel_time
-
- # instant the motion will end
- self.final_instant = self.start_instant + self.duration
-
- # uncomment following line if need output concerning the movement that
- # has just started
- # self.info()
-
- # ASSERTIONS
- if self.positive_dsplmnt:
- assert(self.curr_max_vel_pos >= self.init_pos)
- assert(self.curr_max_vel_pos <= self.final_pos)
- else:
- assert(self.curr_max_vel_pos <= self.init_pos)
- assert(self.curr_max_vel_pos >= self.final_pos)
-
- assert(self.curr_dsplmnt_reach_max_vel >= 0.0)
- assert(self.curr_dsplmnt_reach_min_vel >= 0.0)
-
- assert(self.final_instant >= self.start_instant)
- assert(self.curr_max_vel <= self.max_vel)
- assert(self.start_instant <= self.curr_max_vel_instant)
- assert(self.final_instant >= self.curr_min_vel_instant)
-
- assert(self.curr_max_vel_time > 0.0)
- assert(self.curr_min_vel_time > 0.0)
- assert(self.duration > 0.0)
-
- if self.small_motion:
- assert(self.curr_max_vel_instant == self.curr_min_vel_instant)
- assert(self.curr_at_max_vel_time == 0.0)
- else:
- assert(self.curr_max_vel_instant <= self.curr_min_vel_instant)
- assert(self.curr_at_max_vel_time >= 0.0)
-
- self.inMotion = True
-
- def abortMotion(self, curr_instant=None):
- curr_instant = curr_instant or time.time()
- if not self.inMotion:
- return self.curr_pos
-
- self.curr_pos = self.getCurrentPosition(curr_instant)
- self.inMotion = False
- return self.curr_pos
-
- def isInMotion(self,curr_instant=None):
- curr_instant = curr_instant or time.time()
- #we call getCurrentPosition because inside it updates the inMotion flag
- self.getCurrentPosition(curr_instant)
- return self.inMotion
-
- def setCurrentPosition(self, curr_pos):
- self.curr_pos = curr_pos
- self.init_pos = curr_pos
-
- def getCurrentPosition(self, curr_instant=None):
- curr_instant = curr_instant or time.time()
- self.curr_instant = curr_instant
- pos = None
- if self.inMotion:
- # if motion should be ended...
- if self.curr_instant >= self.final_instant:
- self.inMotion = False
- pos = self.final_pos
- else:
- pos = self.init_pos
- if curr_instant > self.curr_min_vel_instant:
- if self.positive_dsplmnt:
- pos += self.curr_dsplmnt_reach_max_vel
- pos += self.curr_at_max_vel_dsplmnt
- else:
- pos -= self.curr_dsplmnt_reach_max_vel
- pos -= self.curr_at_max_vel_dsplmnt
- dt = curr_instant - self.curr_min_vel_instant
- pos += self.curr_max_vel * dt + 0.5 * self.curr_decel * pow(dt,2)
- elif curr_instant > self.curr_max_vel_instant:
- if self.positive_dsplmnt:
- pos += self.curr_dsplmnt_reach_max_vel
- else:
- pos -= self.curr_dsplmnt_reach_max_vel
- dt = curr_instant - self.curr_max_vel_instant
- pos += self.curr_max_vel * dt
- else:
- dt = curr_instant - self.start_instant
- pos += self.curr_min_vel * dt + 0.5 * self.curr_accel * pow(dt,2)
- else:
- pos = self.curr_pos
- if pos <= self.lower_ls:
- pos = self.lower_ls
- self.inMotion = False
- elif pos >= self.upper_ls:
- pos = self.upper_ls
- self.inMotion = False
- self.curr_pos = pos
- return pos
-
- def setCurrentUserPosition(self, user_pos):
- self.setCurrentPosition(user_pos*self.step_per_unit)
-
- def getCurrentUserPosition(self, curr_instant=None):
- return self.getCurrentPosition(curr_instant=curr_instant) / self.step_per_unit
-
- def hitLowerLimit(self):
- user_pos = self.curr_pos / self.step_per_unit
- return user_pos <= self.lower_ls
-
- def hitUpperLimit(self):
- user_pos = self.curr_pos / self.step_per_unit
- return user_pos >= self.upper_ls
-
- def getLowerLimitSwitch(self):
- return self.lower_ls
-
- def setLowerLimitSwitch(self, user_lower_ls):
- self.lower_ls = user_lower_ls
-
- def getUpperLimitSwitch(self):
- return self.upper_ls
-
- def setUpperLimitSwitch(self, user_upper_ls):
- self.upper_ls = user_upper_ls
-
- def turnOn(self):
- self.power = True
-
- def turnOff(self):
- self.power = False
-
- def isTurnedOn(self):
- return self.power
-
- def hasPower(self):
- return self.power
-
- def setPower(self, power):
- self.power = power
-
- def info(self):
- print "Small movement =",self.small_motion
- print "length =",self.dsplmnt
- print "position where maximum velocity will be reached =",self.curr_max_vel_pos
- print "necessary displacement to reach maximum velocity =",self.curr_dsplmnt_reach_max_vel
- print "necessary displacement to stop from maximum velocity =",self.curr_dsplmnt_reach_min_vel
- print "maximum velocity possible =",self.curr_max_vel
- print "time at top velocity =",self.curr_at_max_vel_time
- print "displacement at top velocity =",self.curr_at_max_vel_dsplmnt
- print "time to reach maximum velocity =",self.curr_max_vel_time
- print "time to reach minimum velocity =",self.curr_min_vel_time
- print "time the motion will take =",self.duration
- print "instant when maximum velocity should be reached =",self.curr_max_vel_instant
- print "instant when should start decelerating =",self.curr_min_vel_instant
- print "instant the motion will end",self.final_instant
- print ""
- print "For long movements (where top vel is possible), necessary displacement to reach maximum velocity =",self.dsplmnt_reach_max_vel
- print "For long movements (where top vel is possible), necessary displacement to stop from maximum velocity =",self.dsplmnt_reach_min_vel
-
-
-class SpringfieldMotorHW(object):
-
- DefaultHost = "localhost"
- DefaultPort = 10123
-
- def __init__(self, host=DefaultHost, port=DefaultPort):
- self.host = host
- self.port = port
- self._motions = {}
-
- def getMotion(self, axis):
- motion = self._motions.get(axis)
- if motion is None:
- self._motions[axis] = motion = Motion()
- return motion
-
- def getState(self, axis):
- motion = self.getMotion(axis)
- motion.getCurrentUserPosition()
- if motion.isInMotion():
- return 2
- if motion.hitLowerLimit():
- return 3
- if motion.hitUpperLimit():
- return 3
- if not motion.hasPower():
- return 4
- return 1
-
- def getStatus(self, axis):
- motion = self.getMotion(axis)
- motion.getCurrentUserPosition()
- status = "Motor HW is ON"
- if motion.isInMotion():
- status = "Motor HW is MOVING"
- if motion.hitLowerLimit():
- status = "Motor HW is in ALARM. Hit hardware lower limit switch"
- if motion.hitUpperLimit():
- status = "Motor HW is in ALARM. Hit hardware upper limit switch"
- if not motion.hasPower():
- status = "Motor is powered off"
- return status
-
- def getLimits(self, axis):
- motion = self.getMotion(axis)
- m.getCurrentUserPosition()
- switchstate = 3*[False,]
- if m.hitLowerLimit():
- switchstate[2] = True
- if m.hitUpperLimit():
- switchstate[1] = True
- return switchstate
-
- def getPosition(self, axis):
- motion = self.getMotion(axis)
- return motion.getCurrentUserPosition()
-
- def getAccelerationTime(self, axis):
- return self.getMotion(axis).getAccelerationTime()
-
- def getDecelerationTime(self, axis):
- return self.getMotion(axis).getDecelerationTime()
-
- def getMinVelocity(self, axis):
- return self.getMotion(axis).getMinVelocity()
-
- def getMaxVelocity(self, axis):
- return self.getMotion(axis).getMaxVelocity()
-
- def getStepPerUnit(self, axis):
- return self.getMotion(axis).getStepPerUnit()
-
- def setAccelerationTime(self, axis, v):
- self.getMotion(axis).setAccelerationTime(v)
-
- def setDecelerationTime(self, axis, v):
- self.getMotion(axis).setDecelerationTime(v)
-
- def setMinVelocity(self, axis, v):
- self.getMotion(axis).setMinVelocity(v)
-
- def setMaxVelocity(self, axis, v):
- self.getMotion(axis).setMaxVelocity(v)
-
- def setStepPerUnit(self, axis, v):
- self.getMotion(axis).setStepPerUnit(v)
-
- def isCloseLoopActive(self, axis):
- return self.getMotion(axis).isCloseLoopActive()
-
- def setCloseLoop(self, axis, v):
- self.getMotion(axis).setCloseLoop(v)
-
- def setCurrentPosition(self, axis, position):
- motion = self.getMotion(axis)
- motion.offset = position - motion.getCurrentUserPosition()
- motion.setCurrentUserPosition(position)
-
- def move(self, axis, position):
- t = time.time()
- motion = self.getMotion(axis)
- motion.startMotion(motion.getCurrentUserPosition(t), position, t)
-
- def stop(self, axis):
- motion = self.getMotion(axis)
- motion.abortMotion()
-
- def abort(self, axis):
- motion = self.getMotion(axis)
- motion.abortMotion()
-
-
-class Channel:
-
- def __init__(self,idx):
- self.idx = idx # 1 based index
- self.value = 0.0
- self.is_counting = False
- self.active = True
-
-
-class SpringfieldCounterHW(object):
-
- DefaultHost = "localhost"
- DefaultPort = 10124
-
- def __init__(self, host=DefaultHost, port=DefaultPort):
- self.host = host
- self.port = port
- self._channels = {}
-
- def getChannel(self, axis):
- channel = self._channels.get(axis)
- if channel is None:
- self._channels[axis] = channel = Channel(axis)
- return channel
-
- def getState(self, axis):
- channel = self.getChannel(axis)
- channel.getCurrentUserValue()
- if channel.isAcquiring():
- return 2
- if not channel.hasPower():
- return 3
- return 1
-
- def getStatus(self, axis):
- channel = self.getChannel(axis)
- channel.getCurrentUserValue()
- status = "Counter HW is ON"
- if channel.isAcquiring():
- status = "Counter HW is ACQUIRING"
- if not channel.hasPower():
- status = "Counter is powered OFF"
- return status
-
- def getValue(self, axis):
- motion = self.getMotion(axis)
- return motion.getCurrentUserPosition() \ No newline at end of file