from mechanism import mechanism import math import ConfigParserRT class filterwheel(mechanism): """Class representing a 4 position filter-wheel type mechanism, based on the generic mechanism class in mechanism.py. It adds attributes for motor steps per rotation and preferred direction of movement. There is optional position feedback checking from grey code microswitches.""" # Mapping between microswitch inputs and filter wheel position statusDict = {4:0, 6:0.5, 2:1, 3:1.5, 7:2, 5:2.5, 1:3, 0:3.5} def __init__(self, names, cortex, icu_num, axis_num, \ base_speed, max_speed, acceleration, deceleration, \ position, steps_per_rev, direction, \ name='filterwheel'): """ Initialiser for filterwheel class. Arguments: names: String containing a comma seperated list of names for the filters. cortex: String containing the name of the cortex based ICU daisy chain instance that this mechanism is a part of. icuNum: Which ICU in the chain this mechanism is connected to. axisNum: Which axis of the ICU the mechansism is connected to. baseSpeed: Starting speed (steps/half steps per sec) maxSpeed: Peak speed (steps/half steps per sec) acceleration: Acceleration (steps/half steps per sec^2) deceleration: Deceleration (steps/half steps per sec^2) position: Initial position of the mechanism (steps) steps_per_rev: Number of motor steps per revolution of the wheel direction: +1 or -1, specifies the direction for rotation name: Label used for logging purposes. """ # Pass the generic parameters to the base class mechanism.__init__(self, cortex, icu_num, axis_num, \ base_speed, max_speed, acceleration, deceleration, \ position, name) # Store the filterwheel specific parameters self.names = names.split(',') self.stepsPerRev = int(steps_per_rev) direction = int(direction) if direction > 0: self.direction = +1 elif direction < 0: self.direction = -1 else: self.logger.critical('Invalid direction "%s" passed to __init__' \ % direction) self.logger.critical('Assuming direction = +1') self.direction = +1 def updateConfig(self, config): """ Should be called by the parent instrument object's destructor to enable status information to be saved to file on exit. Takes a ConfigParserRT.SafeConfigParser object as argument. """ self.logger.debug("updateConfig() called.") if isinstance(config, ConfigParserRT.SafeConfigParser): config.set(self.name, 'steps_per_rev', str(self.stepsPerRev)) config.set(self.name, 'direction', str(self.direction)) # Just call the base class method for the other params mechanism.updateConfig(self, config) else: self.logger.critical("Invalid argument to updateConfig(%s)" \ % repr(config)) self.logger.critical("Unable to save status data") def setupWheel(self): """ Runs through an 'auto-fettling procedure'. """ self.logger.debug('setupWheel() called.') OK = [False, False, False, False] while not OK[0] or not OK[1] or not OK[2] or not OK[3]: status = self.getStatus() # If not at a filter position creep along until we find one. if status % 1: self.logger.debug('Position not found, searching...') OK = [False, False, False, False] search_count = 0 while status % 1: if search_count > 1200: self.logger.critical(\ 'Moved over 90 degrees without finding position!') self.logger.critical('setupWheel() failed!') return self.moveBy(self.direction * 3) search_count += 3 status = self.getStatus() # Set the zero point. self.setPosition(1200 * status * self.direction) # Note current position as OK. self.logger.debug('Located position %i.' % status) OK[status] = True # Move by 90 degrees to next position. self.moveBy(self.direction * 1200) self.logger.info('Filter wheel setup complete.') def getStatus(self): """ Returns 0, 1, 2 or 3 if the wheel in position, 0.5, 1.5, 2.5 or 3.5 if between positions. """ self.logger.debug('getStatus() called') # First check is the icu is active. if self.cortex.isActive(self.icuNum): self.logger.warning('Attempt to getStatus() while active, ignored') else: self.cortex.setOutput(self.axisNum, self.icuNum) status = self.statusDict[self.cortex.getInput(self.icuNum)] self.cortex.setOutput(7, self.icuNum) return status def goTo(self, filter): """ Moves the wheel to the correct position for the given filter number (0, 1, 2 or 3) or filter name (pass a string) . """ self.logger.debug('goTo(%s) called' % filter) if isinstance(filter, int) and filter in (0, 1, 2, 3): self.moveTo(self.direction * self.stepsPerRev * filter / 4.0, \ blocking = True) status = self.getStatus() if status == filter: self.logger.info('goTo(%i) successful' % filter) else: self.logger.warning('goTo(%i) resulted in status %s' \ % (filter, str(status))) elif isinstance(filter, str) and filter in self.names: number = self.names.index(filter) self.moveTo(self.direction * self.stepsPerRev * number / 4.0, \ blocking = True) status = self.getStatus() if status == number: self.logger.info('goTo(%s) successful' % filter) else: self.logger.warning('goTo(%s) resulted in status %s' \ % (filter, str(status))) else: self.logger.critical('Invalid argument to goTo(%s), ignored' \ % filter) def moveBy(self, steps, blocking=True): """ Moves the filter wheel position by a given number of motor steps. Modifies the move to ensure it's in the correct direction and is of magnitude less than a full rotation. """ self.logger.debug('moveBy(%i, %i) called' % (steps, blocking)) # Ensure the move is in the correct direction and of # magnitude less than a full rotation steps = int(math.fmod(steps, self.stepsPerRev)) if steps * self.direction < 0: steps = self.direction * (self.stepsPerRev - abs(steps)) mechanism.moveBy(self, steps, blocking) # Rationalise the new position. self.position = int(math.fmod(self.position, self.stepsPerRev)) if self.position < 0: self.position = self.stepsPerRev - abs(self.position) def moveTo(self, position, blocking=True): self.logger.debug('moveTo(%i, %i) called' % (position, blocking)) self.moveBy(position - self.position, blocking) def setPosition(self, new_position=0): self.logger.debug('setPosition(%i) called' % new_position) # Rationalise the requested new_position new_position = int(math.fmod(new_position, self.stepsPerRev)) if new_position < 0: new_position = self.stepsPerRev - abs(new_position) self.position = new_position