Example #1
0
    def __init__(self):
        ## Maps axis to the handlers for that axis, sorted by their range of
        # motion.
        self.axisToHandlers = depot.getSortedStageMovers()
        if set(self.axisToHandlers.keys()) != {0, 1, 2}:
            raise ValueError('stage mover requires 3 axis: X, Y, and Z')

        # FIXME: we should have sensible defaults.
        self._saved_top = userConfig.getValue('savedTop', default=3010.0)
        self._saved_bottom = userConfig.getValue('savedBottom', default=3000.0)

        ## XXX: We have a single index for all axis, even though each
        ## axis may have a different number of stages.  While we don't
        ## refactor this assumption, we just make copies of the movers
        ## with the most precise movement (issues #413 and #415)
        self.n_stages = max([len(s) for s in self.axisToHandlers.values()])
        for axis, stages in self.axisToHandlers.items():
            stages.extend([stages[-1]] * (self.n_stages - len(stages)))

        ## Indicates which stage handler is currently under control.
        self.curHandlerIndex = 0
        ## Maps Site unique IDs to Site instances.
        self.idToSite = {}

        # Compute the hard motion limits for each axis as the
        # summation of all limits for handlers on that axis.
        hard_limits = [None] * 3
        for axis in range(3):
            lower = 0.0
            upper = 0.0
            # We need set() to avoid duplicated handlers, and we might
            # have duplicated handlers because of the hack to meet
            # cockpit requirements that all axis have the same number
            # of handlers (see comments on issue #413).
            for handler in set(self.axisToHandlers[axis]):
                handler_limits = handler.getHardLimits()
                lower += handler_limits[0]
                upper += handler_limits[1]
            hard_limits[axis] = (lower, upper)
        # Use a tuple to prevent changes to it, and assemble it like
        # this to enable static code analysis.
        self._hard_limits = (hard_limits[0], hard_limits[1], hard_limits[2])

        ## Maps handler names to events indicating if those handlers
        # have stopped moving.
        self.nameToStoppedEvent = {}
        events.subscribe(events.STAGE_MOVER, self.onMotion)
        events.subscribe(events.STAGE_STOPPED, self.onStop)
    def OnSelectROI(self, event: wx.CommandEvent) -> None:
        del event
        image_raw = self._device.acquireRaw()
        if np.max(image_raw) > 10:
            original_dim = np.shape(image_raw)[0]
            resize_dim = 512

            while original_dim % resize_dim != 0:
                resize_dim -= 1

            if resize_dim < original_dim / resize_dim:
                resize_dim = int(np.round(original_dim / resize_dim))

            scale_factor = original_dim / resize_dim
            img = _bin_ndarray(image_raw, new_shape=(resize_dim, resize_dim))
            img = np.require(img, requirements="C")

            last_roi = userConfig.getValue("dm_circleParams")
            last_roi = (
                last_roi[1] / scale_factor,
                last_roi[0] / scale_factor,
                last_roi[2] / scale_factor,
            )

            frame = _ROISelect(self, img, last_roi, scale_factor)
            frame.Show()
        else:
            logger.log.warning("Detected nothing but background noise")
 def checkIfCalibrated(self):
     try:
         self.proxy.get_controlMatrix()
     except Exception as e:
         try:
             controlMatrix = np.asarray(
                 userConfig.getValue("dm_controlMatrix"))
             self.proxy.set_controlMatrix(controlMatrix)
         except Exception:
             raise e
    def updateROI(self):
        circle_parameters = userConfig.getValue("dm_circleParams")
        self.proxy.set_roi(*circle_parameters)

        # Check we have the interferogram ROI
        try:
            self.proxy.get_roi()
        except Exception as e:
            try:
                self.proxy.set_roi(*circle_parameters)
            except Exception:
                raise e
 def checkFourierFilter(self):
     circle_parameters = userConfig.getValue("dm_circleParams")
     try:
         self.proxy.get_fourierfilter()
     except Exception as e:
         try:
             test_image = self.proxy.acquire()
             self.proxy.set_fourierfilter(
                 test_image=test_image,
                 window_dim=50,
                 mask_di=int((2 * circle_parameters[2]) * (3.0 / 16.0)),
             )
         except Exception:
             raise e
    def OnSelectROI(self, event: wx.CommandEvent) -> None:
        del event
        image_raw = self._device.acquireRaw()
        if np.max(image_raw) > 10:
            original_dim = np.shape(image_raw)[0]
            resize_dim = 512

            while original_dim % resize_dim != 0:
                resize_dim -= 1

            if resize_dim < original_dim / resize_dim:
                resize_dim = int(np.round(original_dim / resize_dim))

            scale_factor = original_dim / resize_dim
            img = _bin_ndarray(image_raw, new_shape=(resize_dim, resize_dim))
            img = np.require(img, requirements="C")

            last_roi = userConfig.getValue("dm_circleParams", )
            # We need to check if getValue() returns None, instead of
            # passing a default value to getValue().  The reason is
            # that if there is no ROI at the start, by the time we get
            # here the device initialize has called updateROI which
            # also called getValue() which has have the side effect of
            # setting its value to None.  And we can't set a sensible
            # default at that time because we have no method to get
            # the wavefront camera sensor size.
            if last_roi is None:
                last_roi = (
                    *[d // 2 for d in image_raw.shape],
                    min(image_raw.shape) // 4,
                )

            last_roi = (
                last_roi[1] / scale_factor,
                last_roi[0] / scale_factor,
                last_roi[2] / scale_factor,
            )

            frame = _ROISelect(self, img, last_roi, scale_factor)
            frame.Show()
        else:
            wx.MessageBox(
                "Detected nothing but background noise.",
                caption="No good image acquired",
                style=wx.ICON_ERROR | wx.OK | wx.CENTRE,
            )
    def initialize(self):
        self.proxy = Pyro4.Proxy(self.uri)
        self.proxy.set_trigger(cp_ttype="FALLING_EDGE", cp_tmode="ONCE")
        self.no_actuators = self.proxy.get_n_actuators()

        # Need initial values for system flat calculations
        self.sys_flat_num_it = 10
        self.sys_error_thresh = np.inf
        self.sysFlatNollZernike = np.linspace(start=4,
                                              stop=68,
                                              num=65,
                                              dtype=int)

        # Need intial values for sensorless AO
        self.numMes = 9
        self.num_it = 2
        self.z_max = 1.5
        self.z_min = -1.5
        self.nollZernike = np.asarray([11, 22, 5, 6, 7, 8, 9, 10])

        # Shared state for the new image callbacks during sensorless
        self.actuator_offset = None
        self.camera = None
        self.correction_stack = []
        self.sensorless_correct_coef = np.zeros(self.no_actuators)
        self.z_steps = np.linspace(self.z_min, self.z_max, self.numMes)
        self.zernike_applied = None

        # Excercise the DM to remove residual static and then set to 0 position
        for _ in range(50):
            self.proxy.send(np.random.rand(self.no_actuators))
            time.sleep(0.01)
        self.reset()

        # Load values from config
        try:
            self.updateROI()
        except Exception:
            pass

        try:
            controlMatrix = np.asarray(userConfig.getValue("dm_controlMatrix"))
            self.proxy.set_controlMatrix(controlMatrix)
        except Exception:
            pass
 def applySysFlat(self):
     sys_flat_values = np.asarray(userConfig.getValue("dm_sys_flat"))
     self.proxy.send(sys_flat_values)
Example #9
0
    def __init__(self):
        ## Maps axis to the handlers for that axis, sorted by their range of
        # motion.
        self.axisToHandlers = depot.getSortedStageMovers()
        if set(self.axisToHandlers.keys()) != {0, 1, 2}:
            raise ValueError('stage mover requires 3 axis: X, Y, and Z')

        # FIXME: we should have sensible defaults (see issue #638).
        self._saved_top = userConfig.getValue('savedTop', default=3010.0)
        self._saved_bottom = userConfig.getValue('savedBottom', default=3000.0)

        ## XXX: We have a single index for all axis, even though each
        ## axis may have a different number of stages.  While we don't
        ## refactor this assumption, we just make copies of the movers
        ## with the most precise movement (issues #413 and #415)
        self.n_stages = max([len(s) for s in self.axisToHandlers.values()])
        for axis, stages in self.axisToHandlers.items():
            stages.extend([stages[-1]] * (self.n_stages - len(stages)))

        ## Indicates which stage handler is currently under control.
        self.curHandlerIndex = 0
        ## Maps Site unique IDs to Site instances.
        self.idToSite = {}

        # Compute the hard motion limits for each axis as the
        # summation of all limits for handlers on that axis.
        hard_limits = [None] * 3
        for axis in range(3):
            lower = 0.0
            upper = 0.0
            # We need set() to avoid duplicated handlers, and we might
            # have duplicated handlers because of the hack to meet
            # cockpit requirements that all axis have the same number
            # of handlers (see comments on issue #413).
            for handler in set(self.axisToHandlers[axis]):
                handler_limits = handler.getHardLimits()
                lower += handler_limits[0]
                upper += handler_limits[1]
            hard_limits[axis] = (lower, upper)
        # Use a tuple to prevent changes to it, and assemble it like
        # this to enable static code analysis.
        self._hard_limits = (hard_limits[0], hard_limits[1], hard_limits[2])

        # Compute the initial step sizes.  We have different step
        # sizes for each handler index which maybe doesn't make sense
        # anymore but comes from the time when it were the handlers
        # themselves that kept track of step size.
        self._step_sizes = [
        ]  # type: typing.List[typing.Tuple[float, float, float]]
        for stage_index in range(self.n_stages):
            default_step_sizes = []
            for axis in (0, 1, 2):
                limits = self.axisToHandlers[axis][stage_index].getHardLimits()
                step_size = SensiblePreviousStepSize(
                    (limits[1] - limits[0]) / 100.0)
                default_step_sizes.append(step_size)
            # Default is 1/100 of the axis length but in rectangular
            # stages that will lead to xy with different step sizes so
            # use the min of the two.
            min_xy = min(default_step_sizes[0], default_step_sizes[1])
            self._step_sizes.append((min_xy, min_xy, default_step_sizes[2]))

        ## Maps handler names to events indicating if those handlers
        # have stopped moving.
        self.nameToStoppedEvent = {}
        events.subscribe(events.STAGE_MOVER, self.onMotion)
        events.subscribe(events.STAGE_STOPPED, self.onStop)