Source code for hardware_interfaces.shutter

# Helper modules
from typing import List, Tuple
import logging

# Import relevant modules
import nidaqmx as ni
from nidaqmx import task as ni_task
import time

# Set up logger
logger = logging.getLogger(__name__)


[docs]class Shutter: """ This class can be used to open and close shutters by applying 5V or 0V to their inputs. It is assumed that a National Instruments nidaqmx capable device is used to provide the output voltage. For this a digital output port is used. By default, opening means applying 5V, while closed implies 0 V. The time it takes for a shutter to open/ close is around 10 ms. Waiting 50 ms should be enough to ensure that the process of opening/ closing finishes. Args: device_name (str): Name of device on which the appropriate voltage-out port is located. The name can be found and configured in the National Instruments Software: 'Measurement and Automation Explorer' (MAX). The device name should also be displayed in a pop-up when plugging in the device. * E.g.: "Dev0", "Dev1" etc. channel (str): Name of channel, that is used to send signal. * E.g.: "do0", "do1", "PFI0", "PFI1" etc. waiting_time (float, optional): Time in milliseconds to wait for the shutter to close/open. Defaults to 50 ms. default_position (bool, optional): Set to True if default state is open. Set to False if default state is closed. Defaults to False. open_electrical_state (bool, optional): Set to True if to open the shutter the a digital high signal (5V) needs to be sent. Set to False if to open shutter a digital low (0V) needs to be applied. Defaults to True. name (str, optional): Name / Identifier to give to this shutter. This is relevant for log statements, especially when there is more than one shutter in the setup. Defaults to "XYZ Shutter". Attributes: task (object): Represents a DAQmx Task object, through which all communication with device is managed. current_position (bool): True when shutter is open. False when shutter is closed. channel (object): DAQmx channel object representing the output channel. References: | https://nidaqmx-python.readthedocs.io/en/latest/index.html | https://nidaqmx-python.readthedocs.io/en/latest/task.html """ def __init__( self, device_name: str, channel: str, waiting_time: float = 50, default_position: bool = False, open_electrical_state: bool = True, name: str = "XYZ Shutter", ) -> "Shutter": # Set attributes self.name = name self.default_position = default_position self.open_electrical_state = open_electrical_state self.waiting_time = waiting_time self.current_position = None # Initialise nidaqmx task object self.task = ni_task.Task(self.name) logger.info("Initialized nidaqmx task for {}.".format(self.name)) # Connect to appropriate digital out channel self.channel = self.task.do_channels.add_do_chan( r"/{}/{}".format(device_name, channel) ) # See nidaqmx.task.do_channel documentation logger.info( "Set {} as digital output channel for {}.".format(self.channel, self.name) ) # Set shutter to default state self.move_to_default_position() def __wait(self): """ Puts thread to sleep for specified waiting time in milliseconds using the time module. """ logger.info( "Waiting {} ms for {} to complete movement.".format( self.waiting_time, self.name ) ) time.sleep(self.waiting_time / 1000) # Put thread to sleep logger.info("Waiting time for {} completed.".format(self.name))
[docs] def open(self): """ Opens shutter. Then waits for specified waiting time. """ # Check whether if shutter is already opened if self.current_position == True: logger.info("{} is already opened. Doing nothing.".format(self.name)) return # Exit function / Skip rest of code if ( self.open_electrical_state == True ): # Decide whether high or low needs to be sent. self.task.write(True) logger.info("{} is opening by sending 5V signal.".format(self.name)) elif self.open_electrical_state == False: self.task.write(False) logger.info("{} is opening by sending 0V signal.".format(self.name)) self.__wait() self.current_position = True
[docs] def close(self): """ Closes shutter. Then waits for specified waiting time. """ # Check whether if shutter is already closed if self.current_position == False: logger.info("{} is already closed. Doing nothing.".format(self.name)) return # Exit function / Skip rest of code if ( self.open_electrical_state == True ): # Decide whether high or low needs to be sent. self.task.write(False) logger.info("{} is closing by sending 0V signal.".format(self.name)) elif self.open_electrical_state == False: self.task.write(True) logger.info("{} is closing by sending 5V signal.".format(self.name)) self.__wait() self.current_position = False
[docs] def move_to_default_position(self): """ Moves shutter to its default position. """ logger.info("Moving {} to default position.".format(self.name)) # Manage initialization by setting current position to opposite # of default position. if self.current_position == None: self.current_position = not self.default_position # Move shutter to default postion if self.default_position == True: self.open() elif self.default_position == False: self.close()
[docs] def end(self): """ Moves shutter to default position and ends nidaqmx task. """ logger.info("Moving {} to default position to end task.".format(self.name)) self.move_to_default_position() self.task.close() logger.info("Connection to {} terminated.".format(self.name))
def __enter__(self): return self def __exit__(self, type, value, traceback): self.end()