diff --git a/python/lsst/ts/standardscripts/data/scripts/maintel/mtrotator/move_rotator.py b/python/lsst/ts/standardscripts/data/scripts/maintel/mtrotator/move_rotator.py
old mode 100644
new mode 100755
diff --git a/python/lsst/ts/standardscripts/maintel/mtrotator/move_rotator.py b/python/lsst/ts/standardscripts/maintel/mtrotator/move_rotator.py
index 6d26d1c22..b92cda214 100644
--- a/python/lsst/ts/standardscripts/maintel/mtrotator/move_rotator.py
+++ b/python/lsst/ts/standardscripts/maintel/mtrotator/move_rotator.py
@@ -19,10 +19,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
-__all__ = ["EnableComCam"]
-
-import asyncio
-import warnings
+__all__ = ["MoveRotator"]
import yaml
from lsst.ts.observatory.control.maintel.mtcs import MTCS, MTCSUsages
@@ -52,15 +49,19 @@ class MoveRotator(BaseBlockScript):
def __init__(self, index: int, add_remotes: bool = True) -> None:
super().__init__(index=index, descr="Move Rotator")
- mtcs_usage = None if add_remotes else MTCSUsages.DryTest
-
- self.mtcs = MTCS(self.domain, intended_usage=mtcs_usage, log=self.log)
+ self.mtcs = MTCS(
+ domain=self.domain,
+ intended_usage=None if add_remotes else MTCSUsages.DryTest,
+ log=self.log,
+ )
for comp in self.mtcs.components_attr:
if comp not in ["mtrotator", "mtmount"]:
setattr(self.mtcs.check, comp, False)
- self.rotator_time_per_angle = 5.0 # seconds per degree
+ self.rotator_velocity = 3.5 # degrees per second
+ self.short_timeout = 10 # seconds
+ self.long_timeout = 120 # seconds
@classmethod
def get_schema(cls):
@@ -82,14 +83,14 @@ def get_schema(cls):
minimum: -90
maximum: 90
wait_for_complete:
- description: >-
- whether wait for the rotator to reach the desired angle or
- complete the script before the rotator reaches the desired
+ description: >-
+ whether wait for the rotator to reach the desired angle or
+ complete the script before the rotator reaches the desired
angle.
type: boolean
default: true
required:
- - angle
+ - angle
additionalProperties: false
"""
schema_dict = yaml.safe_load(schema_yaml)
@@ -102,3 +103,24 @@ def get_schema(cls):
]
return schema_dict
+
+ async def configure(self, config):
+ self.target_angle = config.angle
+ self.wait_for_complete = config.wait_for_complete
+
+ await super().configure(config=config)
+
+ def set_metadata(self, metadata):
+ metadata.duration = self.long_timeout
+
+ async def run_block(self):
+ await self.checkpoint(f"Start moving rotator to {self.target_angle} degrees.")
+ await self.mtcs.move_rotator(
+ angle=self.target_angle, wait_for_complete=self.wait_for_complete
+ )
+ if self.wait_for_complete:
+ await self.checkpoint_message(
+ f"Rotator reached {self.target_angle} degrees."
+ )
+ else:
+ await self.checkpoint("Stop script and keep rotator moving.")
diff --git a/tests/test_maintel_mtrotator_move_rotator.py b/tests/test_maintel_mtrotator_move_rotator.py
index c263894ff..c2691b0eb 100644
--- a/tests/test_maintel_mtrotator_move_rotator.py
+++ b/tests/test_maintel_mtrotator_move_rotator.py
@@ -19,6 +19,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
+import asyncio
import unittest
from lsst.ts import standardscripts
@@ -31,8 +32,74 @@ class TestMoveRotator(
async def basic_make_script(self, index):
self.script = MoveRotator(index=index, add_remotes=False)
+ self.start_angle = 0.0 # degrees
+ self.very_short_sleep = 0.1 # seconds
+ self.script.mtcs.move_rotator = unittest.mock.AsyncMock(
+ side_effect=self.mock_move_rotator
+ )
+
return (self.script,)
+ async def mock_move_rotator(self, angle, wait_for_complete):
+ if wait_for_complete is False:
+ await asyncio.sleep(self.very_short_sleep)
+ else:
+ current_angle = self.start_angle
+ while current_angle < angle:
+ await asyncio.sleep(self.very_short_sleep)
+ current_angle += self.script.rotator_velocity * self.very_short_sleep
+
+ async def test_configure_default(self):
+ """Test the default configuration"""
+
+ async with self.make_script():
+ target_angle = 45.0
+
+ await self.configure_script(angle=target_angle)
+
+ assert self.script.target_angle == target_angle
+ assert self.script.wait_for_complete is True
+ assert self.script.program is None
+ assert self.script.reason is None
+ assert self.script.checkpoint_message is None
+
+ async def test_configure_dont_wait_for_complete(self):
+ """Test with the configuration where ``wait_for_complete`` is False"""
+
+ async with self.make_script():
+ target_angle = 45.0
+ wait_for_complete = False
+
+ await self.configure_script(angle=target_angle, wait_for_complete=False)
+
+ assert self.script.target_angle == target_angle
+ assert self.script.wait_for_complete is wait_for_complete
+ assert self.script.program is None
+ assert self.script.reason is None
+ assert self.script.checkpoint_message is None
+
+ async def test_configure_with_program_reason(self):
+ """Testing a valid configuration: with program and reason"""
+
+ # Try configure with a list of valid actuators ids
+ async with self.make_script():
+ self.script.get_obs_id = unittest.mock.AsyncMock(
+ side_effect=["202306060001"]
+ )
+ await self.configure_script(
+ angle=10.0,
+ wait_for_complete=True,
+ program="BLOCK-123",
+ reason="SITCOM-321",
+ )
+
+ assert self.script.program == "BLOCK-123"
+ assert self.script.reason == "SITCOM-321"
+ assert (
+ self.script.checkpoint_message
+ == "MoveRotator BLOCK-123 202306060001 SITCOM-321"
+ )
+
async def test_executable(self):
scripts_dir = standardscripts.get_scripts_dir()
script_path = scripts_dir / "maintel" / "mtrotator" / "move_rotator.py"