Commit 648b675f authored by Marco Buttu's avatar Marco Buttu
Browse files

Completed auto and manual rewinding

parent 78b5f16e
Loading
Loading
Loading
Loading
+45 −21
Original line number Diff line number Diff line
@@ -241,6 +241,7 @@ class Positioner(object):
                        time.sleep(float(self.conf.getAttribute('UpdatingTime')))
                    except OutOfRangeError, ex:
                        logger.logWarning(ex.message)
                        self.control.isRewindingRequired = True
                        if self.control.modes['rewinding'] == 'AUTO':
                            try:
                                self.rewind() 
@@ -251,11 +252,11 @@ class Positioner(object):
                                break
                        else:
                            if self.control.modes['rewinding'] == 'MANUAL':
                                self.control.isRewindingRequired = True
                                logger.logInfo('a derotator rewinding is required')
                                while self.control.isRewindingRequired:
                                    time.sleep(2) # Wait until the user calls a rewind
                            else:
                                logger.logError('wrong rewinding mode: %s' %self.control.modes['rewinding'])
                            break
                    except Exception, ex:
                        logger.logError(ex.message)
                        break
@@ -283,6 +284,8 @@ class Positioner(object):
            raise NotAllowedError('positioner not configured: a setup() is required')
        elif self.isRewinding():
            raise NotAllowedError('another rewinding is active')
        elif not self.isRewindingRequired():
            raise NotAllowedError('no rewinding is required')

        try:
            Positioner.rewindingLock.acquire()
@@ -321,30 +324,51 @@ class Positioner(object):
            raise PositionerError('the number of steps must be positive')

        target = self.control.target
        # space is the distance from the target to the farest limit
        # To be sure, I add a delta of 0.1...
        if target - 0.1 <= self.device.getMinLimit():
            space = abs(self.device.getMaxLimit() - target)
            sign = +1 # The space must be added to the target position
        elif self.device.getMaxLimit() <= target + 0.1:
            space = abs(target - self.device.getMinLimit())
        # The rewinding angle depends of the antenna sector: 
        #
        #   * SOUTH: the derotator must go closer to the lower limit
        #   * NORTH: the derotator must go closer to the higher limit
        #
        # The name space is the distance between the target position and the
        # limit (lower in case of SOUTH, higher in case of NORTH)
        min_limit = self.device.getMinLimit()
        max_limit = self.device.getMaxLimit()
        # To be sure, we add or subtract a delta of 1 to the target
        delta = 1.0
        sector = self.control.scanInfo['sector']
        if sector == Antenna.ANT_SOUTH:
            space = abs(target - min_limit)
            if target + delta >= max_limit:
                sign = -1
                numberOfSteps = int(space // self.device.getStep())
            elif target - delta <= min_limit:
                sign = +1
                numberOfSteps = int(space // self.device.getStep()) + 1
            else:
            lspace = abs(self.device.getMinLimit() - target) # Space on the left
            rspace = abs(self.device.getMaxLimit() - target) # Space on the right
            sign = -1 if lspace >= rspace else 1
            space = max(lspace, rspace)


        maxNumberOfSteps = int(space // self.device.getStep())
                raise ValueError('cannot get the rewinding parameters: ' \
                                 'target %.2f in range' %target)
        elif sector == Antenna.ANT_NORTH:
            space = abs(target - max_limit)
            if target + delta >= max_limit:
                sign = -1
                numberOfSteps = int(space // self.device.getStep()) + 1
            elif target - delta <= min_limit:
                sign = +1
                numberOfSteps = int(space // self.device.getStep())
            else:
                raise ValueError('cannot get the rewinding parameters: ' \
                                 'target %.2f in range' %target)
        else:
            raise ValueError('sector %s unknown' %sector)

        if steps == None:
            n = maxNumberOfSteps
        elif steps <= maxNumberOfSteps:
            n = numberOfSteps
        elif min_limit < target + sign*steps*self.device.getStep() < max_limit:
            n = steps
        else:
            raise PositionerError('target pos: {%.1f} -> max number of steps: {%d} (%s given)'
                    %(target, maxNumberOfSteps, steps))
            raise PositionerError(
                    'target pos: {%.1f} -> rewind of {%d} steps not allowed' \
                    %(target, steps))

        rewinding_value = sign * n * self.device.getStep()
        return (target, rewinding_value)
+0 −32
Original line number Diff line number Diff line
from __future__ import with_statement
import unittest2
import time
from Acspy.Clients.SimpleClient import PySimpleClient
from ComponentErrors import ComponentErrorsEx


class RewindTest(unittest2.TestCase):
    """Test the DewarPositioner.rewind() method"""
    def setUp(self):
        client = PySimpleClient()
        self.positioner = client.getComponent('RECEIVERS/DewarPositioner')
        self.positioner.setup('KKG')

    def tearDown(self):
        if self.positioner.isReady():
            self.positioner.park()

    def test_number_of_steps_oor(self):
        """Raise ComponentErrors when the number of steps is out of range"""
        with self.assertRaisesRegexp(ComponentErrorsEx, 'cannot rewind the derotator'):
            self.positioner.rewind(4)

    def test_not_positive_number_of_steps(self):
        """Raise ComponentErrorsEx when the number of steps is not positive"""
        with self.assertRaisesRegexp(ComponentErrorsEx, 'steps must be positive'):
            self.positioner.rewind(0)



if __name__ == '__main__':
    unittest2.main()
+0 −0

Empty file added.

+0 −135
Original line number Diff line number Diff line
from __future__ import with_statement
import unittest2
import time
import math
from DewarPositioner.posgenerator import PosGenerator
from Antenna import ANT_HORIZONTAL, ANT_NORTH
from Management import MNG_TRACK

from Acspy.Clients.SimpleClient import PySimpleClient
from ComponentErrors import ComponentErrorsEx


class StartUpdatingTest(unittest2.TestCase):
    """Test the DewarPositioner.startUpdating() end-to-end method"""
    def setUp(self):
        self.client = PySimpleClient()
        self.device = self.client.getComponent('RECEIVERS/SRTKBandDerotator')
        self.antenna = self.client.getComponent('ANTENNA/BossSimulator')
        self.positioner = self.client.getComponent('RECEIVERS/DewarPositioner')
        self.positioner.setup('KKG')
        self.positioner.setConfiguration('custom')
        self.lat = 0.689 # 39.5 degrees

    def tearDown(self):
        if self.positioner.isReady():
            self.positioner.stopUpdating()
            time.sleep(1)
            self.positioner.park()
        time.sleep(0.5)
        self.client.releaseComponent('RECEIVERS/DewarPositioner')
        self.client.releaseComponent('ANTENNA/BossSimulator')
        self.device = self.client.releaseComponent('RECEIVERS/SRTKBandDerotator')

    def test_rewind_offset_properly_cleared(self):
        """Verify the startUpdating() clears previous rewinding offsets.

        For instance, in the following case:
        
        - startUpdating() out of range -> rewind        
        - new startUpdating() with (Pis + parallactic) in range

        In the first startUpdating() we want the position to be::

            Pis + Pip + Pid + rewinding_offset

        In the second startUpdating() the position must be::

            Pis + Pip + Pid
        """

        # First step: we choose (az, el) in order to have a parallactic angle
        # out of range. That means the derotator has to rewind
        az, el = 1.2217, 0.6109 # 70 degrees, 35 degrees
        parallactic = PosGenerator.getParallacticAngle(self.lat, az, el) # -63
        min_limit = self.device.getMinLimit() # -85.77 degrees for the K Band
        Pis = -30
        # Final angle -93, lower than the min limit (-85.77)
        self.positioner.setPosition(Pis) 
        self.antenna.setOffsets(az, el, ANT_HORIZONTAL)
        target = Pis + parallactic 
        self.assertLess(target, min_limit)
        # We expect a rewind of 180 degrees: -93 + 180 -> 87
        expected = target + 180
        self.positioner.startUpdating(MNG_TRACK, ANT_NORTH, az, el, 0, 0)
        time.sleep(0.5)
        self.assertAlmostEqual(expected, self.device.getActPosition(), delta=0.1)

        self.positioner.stopUpdating()

        # Second step: we do not call stopUpdating(), and we choose (az, el) 
        # in order to have a parallactic angle in range
        az, el = 5, 0.5 # In radians
        parallactic = PosGenerator.getParallacticAngle(self.lat, az, el) # 58.5
        self.antenna.setOffsets(az, el, ANT_HORIZONTAL)
        target = Pis + parallactic 
        self.assertGreater(target, min_limit)
        # We do not expect a rewind
        expected = target
        self.positioner.startUpdating(MNG_TRACK, ANT_NORTH, az, el, 0, 0)
        time.sleep(0.5)
        self.assertAlmostEqual(expected, self.device.getActPosition(), delta=0.1)

    def test_keep_updating_after_rewind(self):
        """Verify the dewar positioner stills updating after the rewind"""
        Pis = 120
        self.positioner.setPosition(Pis) 

        # First step: we choose (az, el) in order to have a parallactic angle
        # of a just one or two degrees, in order to stay in range. i.e. we
        # can set the following value to start the updating:
        #
        #     >>> az = math.radians(181)
        #     >>> el = math.radians(45)
        #     >>> PosGenerator.getParallacticAngle(self.lat, az, el)
        #     0.77546054825239319
        #
        # and at this point the following in order to go out of range:
        # 
        #    >>> az = math.radians(190)
        #    >>> PosGenerator.getParallacticAngle(self.lat, az, el)
        #    7.7330295207687838
        az = math.radians(181)
        el = math.radians(45)
        parallactic = PosGenerator.getParallacticAngle(self.lat, az, el) # 0.77

        max_limit = self.device.getMaxLimit() # 125.23 degrees for the K Band
        self.antenna.setOffsets(az, el, ANT_HORIZONTAL)
        target = Pis + parallactic 
        self.assertLess(target, max_limit)
        self.positioner.startUpdating(MNG_TRACK, ANT_NORTH, az, el, 0, 0)
        time.sleep(0.5)
        self.assertAlmostEqual(target, self.device.getActPosition(), delta=0.1)
        self.assertTrue(self.positioner.isUpdating())
        self.assertTrue(self.positioner.isTracking())

        # Second step: we set the az, in order to have a parallactic angle
        # that causes an out of range
        # in order to have a parallactic angle in range
        az = math.radians(190)
        self.antenna.setOffsets(az, el, ANT_HORIZONTAL)
        parallactic = PosGenerator.getParallacticAngle(self.lat, az, el) # 7.73
        target = Pis + parallactic
        self.assertGreater(target, max_limit)
        expected = target - 180
        # We expect a rewind
        time.sleep(0.5)
        self.assertAlmostEqual(expected, self.device.getActPosition(), delta=0.1)
        # Verify it keeps the system updating the position
        self.assertFalse(self.positioner.isRewinding())
        self.assertTrue(self.positioner.isUpdating())
        self.assertTrue(self.positioner.isTracking())


if __name__ == '__main__':
    unittest2.main()
+0 −139
Original line number Diff line number Diff line
from __future__ import with_statement
import threading
import time
from math import radians

import unittest2
import mocker

from DewarPositioner.positioner import Positioner, PositionerError, NotAllowedError
from DewarPositioner.cdbconf import CDBConf
from DewarPositionerMockers.mock_components import MockDevice

class RewindTest(unittest2.TestCase):

    def setUp(self):
        self.device = MockDevice()
        self.m = mocker.Mocker()
        self.cdbconf = CDBConf()
        self.cdbconf.attributes['RewindingTimeout'] = '2.0'
        self.p = Positioner(self.cdbconf)
        self.p.setup(siteInfo={}, source=None, device=self.device)
        self.cdbconf.setup('KKG')
        self.cdbconf.setConfiguration('CUSTOM')

    def tearDown(self):
        self.m.restore()
        self.m.verify()

    def test_number_of_steps_oor(self):
        """Raise PositionerError when the number of steps is out of range"""
        with self.assertRaisesRegexp(PositionerError, 'target pos: {0.0}'):
            self.p.rewind(steps=4)

    def test_not_positive_number_of_steps(self):
        """Raise PositionerError when the number of steps is not positive"""
        with self.assertRaisesRegexp(PositionerError, 'steps must be positive$'):
            self.p.rewind(steps=0)

    def test_timeout_exceeded(self):
        """Raise PositionerError when the timeout is exceeded"""
        timeout = float(self.cdbconf.getAttribute('RewindingTimeout'))
        setattr(self.device, 'is_tracking', False)
        with self.assertRaisesRegexp(PositionerError, '%ss exceeded' %timeout):
            self.p.rewind(steps=2)

    def test_is_rewinding(self):
        """Verify the isRewinding(), isRewindingRequired() and isTracking()"""
        n = 2 # Number of steps
        t = threading.Thread(
                   name='isRewinding() test',
                   target=self.p.rewind,
                   args=(n,)
        )
        self.assertEqual(self.p.isRewinding(), False)
        timeout = float(self.cdbconf.getAttribute('RewindingTimeout'))
        sleep_time = float(self.cdbconf.getAttribute('RewindingSleepTime'))
        requests = timeout / sleep_time
        self.device = self.m.patch(self.device)
        self.device.isTracking()
        for i in range(int(requests//2)):
            self.device.isTracking()
            self.m.result(False)
        self.device.isTracking()
        self.m.result(True)
        self.m.count(1, None)
        self.m.replay()
        t.start()
        time.sleep(timeout / 2.0)
        self.assertEqual(self.p.isRewinding(), True)
        self.assertEqual(self.p.isRewindingRequired(), False)
        self.assertEqual(self.p.isTracking(), False)
        time.sleep(timeout)
        self.assertEqual(self.p.isRewinding(), False)

    def test_tracking_when_rewinding_required(self):
        """Verify the tracking flag is False when a rewinding is required"""
        self.p = self.m.patch(self.p)
        self.p.isRewindingRequired()
        self.m.result(True)
        self.m.count(2)
        self.m.replay()
        self.assertEqual(self.p.isRewindingRequired(), True)
        self.assertEqual(self.p.isRewinding(), False)
        self.assertEqual(self.p.isTracking(), False)

    def test_position_after_rewinding_from0(self):
        """Verify the value of the position after the rewinding (from 0)"""
        n = 2
        self.p.setPosition(0)
        expected = sum(self.p.getRewindingParameters(n))
        self.p.rewind(steps=n)
        self.assertEqual(self.device.getActPosition(), expected)

    def test_position_after_rewinding_from100(self):
        """Verify the value of the position after the rewinding (from 100)"""
        self.p.setRewindingMode('MANUAL')
        self.p.setPosition(100)
        expected = sum(self.p.getRewindingParameters())
        self.p.rewind()
        self.assertEqual(self.device.getActPosition(), expected)

    def test_position_after_auto_rewinding_from100(self):
        """Verify the value of the position after auto rewinding (from 0)"""
        self.p.setRewindingMode('AUTO')
        self.p.setPosition(100)
        n = 2
        expected = sum(self.p.getRewindingParameters(n))
        self.p.rewind(steps=n)
        self.assertEqual(self.device.getActPosition(), expected)

    def test_xxxAutoRewindingSteps(self):
        """Verify setAutoRewindingSteps() and clearAutoRewindingSteps()"""
        n = 1
        # NotAllowedError is raised in case of a number of steps too large
        max_limit = self.device.getMaxLimit() 
        min_limit = self.device.getMinLimit()
        max_rewinding_steps = (max_limit - min_limit) // self.device.getStep()
        with self.assertRaisesRegexp(NotAllowedError, 'max number of steps'):
            self.p.setAutoRewindingSteps(max_rewinding_steps + 1)
        # NotAllowedError is raised in case of a number of steps not positive
        with self.assertRaisesRegexp(NotAllowedError, 'must be positive'):
            self.p.setAutoRewindingSteps(0)
        self.p.setPosition(100)
        self.p.setAutoRewindingSteps(n)
        expected = sum(self.p.getRewindingParameters(n))
        self.p.rewind(self.p.getAutoRewindingSteps())
        self.assertEqual(self.device.getActPosition(), expected)
        self.p.setPosition(100)
        self.p.clearAutoRewindingSteps()
        expected = sum(self.p.getRewindingParameters())
        self.p.rewind(self.p.getAutoRewindingSteps() or None)
        self.assertEqual(self.device.getActPosition(), expected)
        self.p.park()
        # A NotAllowedError is raised in case the system is not configured
        with self.assertRaisesRegexp(NotAllowedError, 'not configured'):
            self.p.setAutoRewindingSteps(n)

if __name__ == '__main__':
    unittest2.main()
Loading