def _init(self): Logger().trace("MerlinOrionAxis._init()") AbstractHardwarePlugin._init(self) AbstractAxisPlugin._init(self) self._hardware = MerlinOrionHardware() self.__run = False self.__driveEvent = threading.Event() self.__setPoint = None self.__currentPos = None
class MerlinOrionShutter(AbstractHardwarePlugin, ShutterPlugin): def __init__(self, *args, **kwargs): """ """ AbstractHardwarePlugin.__init__(self, *args, **kwargs) ShutterPlugin.__init__(self, *args, **kwargs) def _init(self): Logger().trace("MerlinOrionShutter._init()") AbstractHardwarePlugin._init(self) ShutterPlugin._init(self) self._hardware = MerlinOrionHardware() def _defineConfig(self): AbstractHardwarePlugin._defineConfig(self) ShutterPlugin._defineConfig(self) def _triggerOnShutter(self): """ Set the shutter on. """ self._hardware.setOutput(True) def _triggerOffShutter(self): """ Set the shutter off. """ self._hardware.setOutput(False) def init(self): Logger().trace("MerlinOrionShutter.init()") self._hardware.setAxis(AXIS_TABLE[self.capacity]), AbstractHardwarePlugin.init(self) ShutterPlugin.init(self) def shutdown(self): Logger().trace("MerlinOrionShutter.shutdown()") self._triggerOffShutter() AbstractHardwarePlugin.shutdown(self) ShutterPlugin.shutdown(self)
def _init(self): Logger().trace("MerlinOrionShutter._init()") AbstractHardwarePlugin._init(self) ShutterPlugin._init(self) self._hardware = MerlinOrionHardware()
class MerlinOrionAxis(AbstractHardwarePlugin, AbstractAxisPlugin, QtCore.QThread): """ """ def __init__(self, *args, **kwargs): AbstractHardwarePlugin.__init__(self, *args, **kwargs) # Only 1? AbstractAxisPlugin.__init__(self, *args, **kwargs) QtCore.QThread.__init__(self) def __onPositionUpdate(self, yaw, pitch): """ Refresh position according to new pos. @param yaw: yaw axis value @type yaw: float @param pitch: pitch axix value @type pitch: float """ if self.capacity == 'yawAxis': self.__currentPos = yaw else: self.__currentPos = pitch def _init(self): Logger().trace("MerlinOrionAxis._init()") AbstractHardwarePlugin._init(self) AbstractAxisPlugin._init(self) self._hardware = MerlinOrionHardware() self.__run = False self.__driveEvent = threading.Event() self.__setPoint = None self.__currentPos = None def _defineConfig(self): AbstractAxisPlugin._defineConfig(self) AbstractHardwarePlugin._defineConfig(self) self._addConfigKey('_alternateDrive', 'ALTERNATE_DRIVE', default=DEFAULT_ALTERNATE_DRIVE) self._addConfigKey('_alternateDrive', 'ALTERNATE_DRIVE_ANGLE', default=DEFAULT_ALTERNATE_DRIVE_ANGLE) self._addConfigKey('_inertiaAngle', 'INERTIA_ANGLE', default=DEFAULT_INERTIA_ANGLE) self._addConfigKey('_overwriteEncoderFullCircle', 'OVERWRITE_ENCODER_FULL_CIRCLE', default=DEFAULT_OVERWRITE_ENCODER_FULL_CIRCLE) self._addConfigKey('_encoderFullCircle', 'ENCODER_FULL_CIRCLE', default=DEFAULT_ENCODER_FULL_CIRCLE) def activate(self): Logger().trace("MerlinOrionPlugin.activate()") AbstractAxisPlugin.activate(self) # Start the thread self.start() def deactivate(self): Logger().trace("MerlinOrionPlugin.deactivate()") # Stop the thread self._stopThread() AbstractAxisPlugin.deactivate(self) def init(self): Logger().trace("MerlinOrionAxis.init()") self._hardware.setAxis(AXIS_TABLE[self.capacity]), AbstractHardwarePlugin.init(self) if self._config['OVERWRITE_ENCODER_FULL_CIRCLE']: self._hardware.overwriteEncoderFullCircle(self._config['ENCODER_FULL_CIRCLE']) # Connect Spy update signal self.connect(Spy(), QtCore.SIGNAL("update"), self.__onPositionUpdate, QtCore.Qt.BlockingQueuedConnection) def shutdown(self): Logger().trace("MerlinOrionAxis.shutdown()") self.stop() AbstractHardwarePlugin.shutdown(self) AbstractAxisPlugin.shutdown(self) # Disconnect Spy update signal self.disconnect(Spy(), QtCore.SIGNAL("update"), self.__onPositionUpdate) def configure(self): AbstractAxisPlugin.configure(self) AbstractHardwarePlugin.configure(self) if self._config['OVERWRITE_ENCODER_FULL_CIRCLE']: self._hardware.overwriteEncoderFullCircle(self._config['ENCODER_FULL_CIRCLE']) else: self._hardware.useFirmwareEncoderFullCircle() def run(self): """ Main entry of the thread. """ threadName = "%s_%s" % (self.name, self.capacity) threading.currentThread().setName(threadName) Logger().debug("MerlinOrionAxis.run(): start thread") self.__run = True while self.__run: self.__driveEvent.wait() # Check again __run flag to see if _stopThread has been called if self.__run: # Choose alternate drive if needed currentPos = self.read() if self._config['ALTERNATE_DRIVE'] and \ 1.1 * self._config['INERTIA_ANGLE'] < abs(self.__setPoint - currentPos) < self._config['ALTERNATE_DRIVE_ANGLE']: self._alternateDrive(self.__setPoint) # Use standard drive to reach the position if self.__driveEvent.isSet(): self._directDrive(self.__setPoint) Logger().debug("MerlinOrionAxis.run(): thread terminated") def _stopThread(self): """ Stop the thread. """ self.__run = False self.__driveEvent.set() self.wait() def read(self): pos = self._hardware.read() - self._offset return pos def drive(self, pos, useOffset=True, wait=True): Logger().debug("MerlinOrionAxis.drive(): '%s' drive to %.1f" % (self.capacity, pos)) currentPos = self.read() self._checkLimits(pos) # Only move if needed if abs(pos - currentPos) > AXIS_ACCURACY or not useOffset: if not useOffset: # Move before if? pos -= self._offset self.__setPoint = pos self.__driveEvent.set() # Start thread action # Wait end of movement if wait: self.waitEndOfDrive() def _directDrive(self, pos): """ Direct drive. This method uses the Merlin/Orion internal closed loop regulation. @param pos: position to reach, in ° @type pos: float """ Logger().trace("MerlinOrionAxis._directDrive()") pos += self._offset self._hardware.drive(pos) self.__driveEvent.clear() def _alternateDrive(self, pos): """ Alternate drive. This method implements an external closed-loop regulation. It is faster for angles < 6-7°, because in this case, the head does not accelerate to full speed, but rather stays at very low speed. @param pos: position to reach, in ° @type pos: float """ Logger().trace("MerlinOrionAxis._alternateDrive()") # Compute initial direction # BUG!!! Arm side is not taken in account!!! if pos > self.__currentPos: dir_ = '+' else: dir_ = '-' self._hardware.startJog(dir_, MANUAL_SPEED_TABLE['alternate']) # Check when to stop #while ((dir_ == '-' and self.__currentPos - pos > self._config['INERTIA_ANGLE']) or \ #(dir_ == '+' and pos - self.__currentPos > self._config['INERTIA_ANGLE'])) and \ #self.__driveEvent.isSet(): while abs(self.__currentPos - pos) > self._config['INERTIA_ANGLE'] and self.__driveEvent.isSet(): time.sleep(config.SPY_REFRESH_DELAY / 1000.) self._hardware.stop() def waitEndOfDrive(self): while self.isMoving(): time.sleep(config.SPY_REFRESH_DELAY / 1000.) self.waitStop() def startJog(self, dir_): self._hardware.startJog(dir_, MANUAL_SPEED_TABLE[self._manualSpeed]) def stop(self): self.__driveEvent.clear() self._hardware.stop() def waitStop(self): previousPos = self.__currentPos time.sleep(config.SPY_REFRESH_DELAY / 1000.) while abs(previousPos - self.__currentPos) > AXIS_ACCURACY: previousPos = self.__currentPos time.sleep(config.SPY_REFRESH_DELAY / 1000.) def isMoving(self): status = self._hardware.getStatus() if status[1] != '0' or self.__driveEvent.isSet(): return True else: return False