.. currentmodule:: sardana.pool.poolmotor

.. _sardana-motor-api:

===================
Motor API reference
===================

The motor is one of the most used elements in sardana. A motor represents
anything that can be *changed* (and can potentially take some time to do it).

This chapter explains the generic motor :term:`API` in the context of sardana.
In sardana there are, in fact, two Motor :term:`API`\s. To better explain why,
let's consider the case were sardana server is running as a Sardana Tango
device server:

.. image:: /_static/sardana_server_internal_motor.png
    :width: 680
    :align: center

Every motor in sardana is represented in the sardana kernel as a
:class:`PoolMotor`. The :class:`PoolMotor` :term:`API` is not directly
accessible from outside the sardana server. This is a low level :term:`API`
that is only accessbile to someone writing a server extension to sardana. At
the time of writing, the only available sardana server extension is Tango.

The second motor interface consists on the one provided by the server extension,
which is in this case the one provided by the Tango motor device interface:
:class:`~sardana.tango.pool.Motor.Motor`. The Tango motor interface tries to
mimic the as closely as possible the :class:`PoolMotor` :term:`API`.

.. seealso:: 
    
    :ref:`sardana-motor-overview`
        the motor overview 

    :class:`~sardana.tango.pool.Motor.Motor`
        the motor tango device :term:`API`
    
..    :class:`~sardana.pool.poolmotor.PoolMotor`
..        the motor class :term:`API`

A motor will have, at least, a ``state``, and a ``position``. The state
indicates at any time if the motor is stopped, in alarm or moving. The
position, indicates the current :term:`user position`. Unless a motor
controller is specifically programmed not to, it's motors will also have:

**limit switches**
    the three limit switches (home, upper and lower). Each switch is
    represented by a boolean value: False means inactive while True means
    active.
    
    low level :attr:`PoolMotor` API.
    
    high level Tango Motor API: limit_switches tango attribute
        
**acceleration**
    motor acceleration (usually acceleration time in seconds, but it's up to
    the motor controller class to decide)
    
    :attr:`~PoolMotor.acceleration`
    
**deceleration**
    motor deceleration (usually deceleration time in seconds, but it's up to
    the motor controller class to decide)

    :attr:`~PoolMotor.deceleration`
    
**velocity**
    top velocity

    :attr:`~PoolMotor.velocity`

**base rate**
    initial velocity

    :attr:`~PoolMotor.base_rate`

**dial position**
    the :term:`dial position`

    :attr:`~PoolMotor.dial_position`

**offset**
    the offset to be applied in the motor position computation [default: 0.0]

    :attr:`~PoolMotor.offset`

**sign**
    the sign to be applied in the motor position computation [default: 1,
    possible values are (1, -1)]

    :attr:`~PoolMotor.sign`

**steps per unit**
    This is the number of motor steps per :term:`user position` [default:
    1.0]

    :attr:`~PoolMotor.step_per_unit`

**backlash**
    If this is defined to be something different than 0, the motor will
    always stop the motion coming from the same mechanical direction. This
    means that it could be possible to ask the motor to go a little bit after
    the desired position and then to return to the desired position. The value
    is the number of steps the motor will pass the desired position if it
    arrives from the "wrong" direction. This is a signed value. If the sign is
    positive, this means that the authorized direction to stop the motion is
    the increasing motor position direction. If the sign is negative, this
    means that the authorized direction to stop the motion is the decreasing
    motor position direction. 

    :attr:`~PoolMotor.backlash`
    
**instability time**
    This property defines the time in milliseconds that the software
    managing a motor movement will wait between it detects the end of the
    motion and the last motor position reading. It is typically used for motors
    that move mechanics which have an instability time after each motion.
    
    :attr:`~PoolMotor.instability_time`

The available operations are:

start move absolute (:term:`user position`\)
    starts to move the motor to the given absolute user position
    
    :meth:`~PoolMotor.start_move`

stop
    stops the motor in an orderly fashion
    
abort
    stops the motor motion as fast as possible (possibly without
    deceleration time and loss of position)

release
    Release hung motion e.g. due to the hardware controller that
    got hung. You should first try stop/abort.

Motor state
-----------

On a sardana tango server, the motor state can be obtained by reading the state
attribute or by executing the state command. The diagram shows the internal
sequence of calls.

.. image:: /_static/sardana_server_internal_motor_read_state_flow.png
    :width: 680
    :align: center

.. _sardana-motor-api-position:

Motor position
--------------

The motor's current :term:`user position` can be obtained by reading the
position attribute. The diagram shows the internal sequence of calls.

.. image:: /_static/sardana_server_internal_motor_read_position_flow.png
    :width: 680
    :align: center

Motion
------

The most useful thing to do with a motor is, of course, to move it. To move a
motor to another absolute :term:`user position` you have to write the value
into the position attribute.

.. image:: /_static/sardana_server_internal_motor_write_position_flow.png
    :width: 680
    :align: center

Before allowing a movement, some pre-conditions are automatically checked by
tango (not represented in the diagram):

    - motor is in a proper state;
    - requested position is within the allowed motor boundaries (if
      defined)

Then, the :term:`dial position` is calculated taking into account the *offset*,
*signal* as well as a possible *backlash*.

Afterward, and because the motor may be part of a pseudo motor system, other
pre-conditions are checked:

    - is the final :term:`dial position` (including backlash) within the
      motor boundaries (if defined)
    - will the resulting motion end in an allowed position for all the
      pseudo motors that depend on this motor

After all pre-conditions are checked, the motor will deploy a motion *job* into
the sardana kernel engine which will trigger a series of calls to the
underlying motor controller.

The motor awaits for the :meth:`~sardana.pool.controller.Startable.PreStartOne`
to signal that the motion will be possible to return successfully from the move
request.

.. TODO: Once the "caption" bug is fixed (see the next TODO) move the following
..      text to the figure caption

The following diagram shows the motion state machine of a motor. The black state 
transitions are the ones which can be triggered by a *user*.
For simplicity, only the most relevant states involved in a motor
motion are shown. Error states are omitted.

.. graphviz:: motion.dot
    :alt: Basic motion diagram

.. TODO: Figure captions for figures using graphviz (:caption:) does not work
..       for version 1.3.1 of Sphinx 
..       (see: https://github.com/sphinx-doc/sphinx/issues/1788)
..       It will be fixed in next Sphinx release.
..    :caption:
..        Basic motion diagram. The black state transitions are the ones which
..        can be triggered by a *user*.
..        For simplicity, only the most relevant states involved in a motor
..        motion are shown. Error states are omitted
