def __init__(self, name, role, parent, ranges=None, **kwargs): axes = { "pressure": model.Axis(unit="Pa", choices={ PRESSURE_VENTED: "vented", PRESSURE_PUMPED: "vacuum" }) } model.Actuator.__init__(self, name, role, parent=parent, axes=axes, **kwargs) # last official position if self.GetStatus() == 0: self._position = PRESSURE_PUMPED else: self._position = PRESSURE_VENTED # RO, as to modify it the client must use .moveRel() or .moveAbs() self.position = model.VigilantAttribute({"pressure": self._position}, unit="Pa", readonly=True) # Almost the same as position, but gives the current position self.pressure = model.VigilantAttribute(self._position, unit="Pa", readonly=True) # will take care of executing axis move asynchronously self._executor = CancellableThreadPoolExecutor( max_workers=1) # one task at a time
def __init__(self, name, role, **kwargs): """ Initialises the component """ # TODO: or just provide .targetPressure (like .targetTemperature) ? # Or maybe provide .targetPosition: position that would be reached if # all the requested move were instantly applied? # TODO: support multiple pressures (low vacuum, high vacuum) axes = { "pressure": model.Axis(unit="Pa", choices={ PRESSURE_VENTED: "vented", PRESSURE_PUMPED: "vacuum" }) } model.Actuator.__init__(self, name, role, axes=axes, **kwargs) # For simulating moves self._position = PRESSURE_PUMPED # last official position self._goal = PRESSURE_PUMPED self._time_goal = 0 # time the goal was/will be reached self._time_start = 0 # time the move started # RO, as to modify it the client must use .moveRel() or .moveAbs() self.position = model.VigilantAttribute({"pressure": self._position}, unit="Pa", readonly=True) # Almost the same as position, but gives the current position self.pressure = model.VigilantAttribute(self._position, unit="Pa", readonly=True) # will take care of executing axis move asynchronously self._executor = CancellableThreadPoolExecutor( max_workers=1) # one task at a time
def __init__(self, name, role, port, axes, ustepsize, **kwargs): """ port (str): port name (only if sn is not specified) axes (list of str): names of the axes, from the 1st to the 3rd. ustepsize (list of float): size of a microstep in m inverted (set of str): names of the axes which are inverted (IOW, either empty or the name of the axis) """ if len(axes) != 3: raise ValueError("Axes must be a list of 3 axis names (got %s)" % (axes, )) self._axes_names = axes # axes names in order if len(axes) != len(ustepsize): raise ValueError("Expecting %d ustepsize (got %s)" % (len(axes), ustepsize)) for sz in ustepsize: if sz > 10e-3: # sz is typically ~1µm, so > 1 cm is very fishy raise ValueError("ustepsize should be in meter, but got %g" % (sz, )) self._ustepsize = ustepsize self._serial = self._openSerialPort(port) self._port = port self._ser_access = threading.Lock() self._target = 1 # TODO: need to be selected by user? When is it not 1? self._resynchonise() modl, vmaj, vmin = self.GetVersion() if modl != 3110: logging.warning( "Controller TMCM-%d is not supported, will try anyway", modl) if name is None and role is None: # For scan only return # will take care of executing axis move asynchronously self._executor = CancellableThreadPoolExecutor( max_workers=1) # one task at a time axes_def = {} for n, sz in zip(self._axes_names, self._ustepsize): # Mov abs supports ±2³¹ but the actual position is only within ±2²³ rng = [(-2**23) * sz, (2**23 - 1) * sz] # Probably not that much, but there is no info unless the axis has # limit switches and we run a referencing axes_def[n] = model.Axis(range=rng, unit="m") model.Actuator.__init__(self, name, role, axes=axes_def, **kwargs) driver_name = driver.getSerialDriver(self._port) self._swVersion = "%s (serial driver: %s)" % (odemis.__version__, driver_name) self._hwVersion = "TMCM-%d (firmware %d.%02d)" % (modl, vmaj, vmin) self.position = model.VigilantAttribute({}, unit="m", readonly=True) self._updatePosition() # TODO: add support for changing speed. cf p.68: axis param 4 + p.81 + TMC 429 p.6 self.speed = model.VigilantAttribute({}, unit="m/s", readonly=True) self._updateSpeed()
def __init__(self, cnvs): super(PointSelectOverlay, self).__init__(cnvs) # Prevent the cursor from resetting on clicks # Physical position of the last click self.v_pos = model.VigilantAttribute(None) self.w_pos = model.VigilantAttribute(None) self.p_pos = model.VigilantAttribute(None)
def __init__(self, name, role, positions, has_pressure=True, **kwargs): """ Initialises the component positions (list of str): each pressure positions supported by the component (among the allowed ones) has_pressure (boolean): if True, has a pressure VA with the current pressure. """ # TODO: or just provide .targetPressure (like .targetTemperature) ? # Or maybe provide .targetPosition: position that would be reached if # all the requested move were instantly applied? chp = {} for p in positions: try: chp[PRESSURES[p]] = p except KeyError: raise ValueError("Pressure position %s is unknown" % (p, )) axes = {"vacuum": model.Axis(unit="Pa", choices=chp)} model.Actuator.__init__(self, name, role, axes=axes, **kwargs) # For simulating moves self._position = PRESSURE_VENTED # last official position self._goal = PRESSURE_VENTED self._time_goal = 0 # time the goal was/will be reached self._time_start = 0 # time the move started # RO, as to modify it the client must use .moveRel() or .moveAbs() self.position = model.VigilantAttribute({"vacuum": self._position}, unit="Pa", readonly=True) if has_pressure: # Almost the same as position, but gives the current position self.pressure = model.VigilantAttribute(self._position, unit="Pa", readonly=True) self._press_timer = util.RepeatingTimer( 1, self._updatePressure, "Simulated pressure update") self._press_timer.start() else: self._press_timer = None # Indicates whether the chamber is opened or not # Just pretend it's always closed, and allow the user to change that # for instance via CLI. self.opened = model.BooleanVA(False) # will take care of executing axis move asynchronously self._executor = CancellableThreadPoolExecutor( max_workers=1) # one task at a time
def __init__(self, name, coordinates, roc_2, roc_3, asm, multibeam, descanner, detector, overlap=0, pre_calibrate=False): """ :param name: (str) Name of the region of acquisition (ROA). It is the name of the megafield (id) as stored on the external storage. :param coordinates: (float, float, float, float) xmin, ymin, xmax, ymax Bounding box coordinates of the ROA in [m]. The coordinates are in the sample carrier coordinate system, which corresponds to the component with role='stage'. :param roc_2: (FastEMROC) Corresponding region of calibration (ROC). Used for dark offset and digital gain calibration. :param roc_3: (FastEMROC) Corresponding region of calibration (ROC). Used for the final scanner rotation, final scanning amplitude and cell translation (cell stitching) calibration (field corrections). :param asm: (technolution.AcquisitionServer) The acquisition server module component. :param multibeam: (technolution.EBeamScanner) The multibeam scanner component of the acquisition server module. :param descanner: (technolution.MirrorDescanner) The mirror descanner component of the acquisition server module. :param detector: (technolution.MPPC) The detector object to be used for collecting the image data. :param overlap: (float), optional The amount of overlap required between single fields. An overlap of 0.2 means that two neighboring fields overlap by 20%. By default, the overlap is 0, this means there is no overlap and one field is exactly next to the neighboring field. :param pre_calibrate: (bool) If True run pre-calibrations before each ROA acquisition. """ self.name = model.StringVA(name) self.coordinates = model.TupleContinuous(coordinates, range=((-1, -1, -1, -1), (1, 1, 1, 1)), cls=(int, float), unit='m') self.roc_2 = model.VigilantAttribute(roc_2) self.roc_3 = model.VigilantAttribute(roc_3) self._asm = asm self._multibeam = multibeam self._descanner = descanner self._detector = detector # List of tuples(int, int) containing the position indices of each field to be acquired. # Automatically updated when the coordinates change. self.field_indices = [] self.overlap = overlap self.pre_calibrate = pre_calibrate self.coordinates.subscribe(self.on_coordinates, init=True)
def __init__(self, microscope, main_app): super(MonoScanPlugin, self).__init__(microscope, main_app) # Can only be used on a Sparc with a monochromator if not microscope: return try: self.ebeam = model.getComponent(role="e-beam") self.mchr = model.getComponent(role="monochromator") self.sgrh = model.getComponent(role="spectrograph") except LookupError: logging.debug("No mochromator and spectrograph found, cannot use the plugin") return self.addMenu("Acquisition/Monochromator scan...", self.start) # the SEM survey stream (will be updated when showing the window) self._survey_s = None # Create a stream for monochromator scan self._mchr_s = MonochromatorScanStream("Spectrum", self.mchr, self.ebeam, self.sgrh) # The settings to be displayed in the dialog # Trick: we use the same VAs as the stream, so they are directly synchronised self.startWavelength = self._mchr_s.startWavelength self.endWavelength = self._mchr_s.endWavelength self.numberOfPixels = self._mchr_s.numberOfPixels self.dwellTime = self._mchr_s.dwellTime self.filename = model.StringVA("a.h5") self.expectedDuration = model.VigilantAttribute(1, unit="s", readonly=True) # Update the expected duration when values change self.dwellTime.subscribe(self._update_exp_dur) self.numberOfPixels.subscribe(self._update_exp_dur)
def __init__(self, name, role, axes, ranges=None, **kwargs): """ axes (set of string): names of the axes """ assert len(axes) > 0 if ranges is None: ranges = {} axes_def = {} self._position = {} init_speed = {} for a in axes: rng = ranges.get(a, [-0.1, 0.1]) axes_def[a] = model.Axis(unit="m", range=rng, speed=[0., 10.]) # start at the centre self._position[a] = (rng[0] + rng[1]) / 2 init_speed[a] = 10.0 # we are super fast! model.Actuator.__init__(self, name, role, axes=axes_def, **kwargs) # RO, as to modify it the client must use .moveRel() or .moveAbs() self.position = model.VigilantAttribute(self._applyInversionAbs( self._position), unit="m", readonly=True) self.speed = model.MultiSpeedVA(init_speed, [0., 10.], "m/s")
def __init__(self, name, role, wlp, **kwargs): """ wlp (list of floats): polynomial for conversion from distance from the center of the CCD to wavelength (in m). So, typically, a first order polynomial contains as first element the center wavelength, and as second element the light dispersion (in m/m). """ if kwargs.get("inverted", None): raise ValueError("Axis of spectrograph cannot be inverted") if not isinstance(wlp, list) or len(wlp) < 1: raise ValueError("wlp need to be a list of at least one float") self._swVersion = "N/A (Odemis %s)" % odemis.__version__ self._hwVersion = name self._wlp = wlp pos = {"wavelength": self._wlp[0]} wla = model.Axis(range=(0, 2400e-9), unit="m") model.Actuator.__init__(self, name, role, axes={"wavelength": wla}, **kwargs) self.position = model.VigilantAttribute(pos, unit="m", readonly=True)
def __init__(self, fake_img): """ Use .fake_img to change the image sent by the ccd Args: fake_img: 2D DataArray """ super(FakeCCD, self).__init__("testccd", "ccd") self.exposureTime = model.FloatContinuous(0.1, (1e-6, 1000), unit="s") res = fake_img.shape[1], fake_img.shape[0] # X, Y depth = 2 ** (fake_img.dtype.itemsize * 8) self.shape = (res[0], res[1], depth) self.binning = model.TupleContinuous((1, 1), [(1, 1), (8, 8)], cls=(int, long, float), unit="") self.resolution = model.ResolutionVA(res, [(1, 1), res]) self.readoutRate = model.FloatVA(1e9, unit="Hz", readonly=True) pxs_sens = fake_img.metadata.get(model.MD_SENSOR_PIXEL_SIZE, (10e-6, 10e-6)) self.pixelSize = model.VigilantAttribute(pxs_sens, unit="m", readonly=True) self.data = CCDDataFlow(self) self._acquisition_thread = None self._acquisition_lock = threading.Lock() self._acquisition_init_lock = threading.Lock() self._acquisition_must_stop = threading.Event() self.fake_img = fake_img self._metadata = fake_img.metadata
def __init__(self, name, role, port, bands, _scan=False, **kwargs): """ port (string): name of the serial port to connect to. Can be a pattern, in which case, all the ports fitting the pattern will be tried, and the first one which looks like an FW102C will be used. bands (dict 1<=int<=12 -> 2-tuple of floats > 0 or str): filter position -> lower and higher bound of the wavelength (m) of the light which goes _through_. If it's a list, it implies that the filter is multi-band. _scan (bool): only for internal usage raise IOError if no device answering or not a compatible device """ self._ser_access = threading.Lock() self._port = self._findDevice(port) logging.info("Found FW102C device on port %s", self._port) if _scan: return # check bands contains correct data self._maxpos = self.GetMaxPosition() if not bands: raise ValueError("Argument bands must contain at least one band") try: for pos, band in bands.items(): if not 1 <= pos <= self._maxpos: raise ValueError("Filter position should be between 1 and " "%d, but got %d." % (self._maxpos, pos)) # To support "weird" filter, we accept strings if isinstance(band, basestring): if not band.strip(): raise ValueError("Name of filter %d is empty" % pos) else: self._checkBand(band) except Exception: logging.exception("Failed to parse bands %s", bands) raise axes = {"band": model.Axis(choices=bands)} model.Actuator.__init__(self, name, role, axes=axes, **kwargs) driver_name = driver.getSerialDriver(self._port) self._swVersion = "%s (serial driver: %s)" % (odemis.__version__, driver_name) self._hwVersion = self._idn # will take care of executing axis move asynchronously self._executor = CancellableThreadPoolExecutor( max_workers=1) # one task at a time self._speed = self.GetSpeed() curpos = self.GetPosition() self.position = model.VigilantAttribute({"band": curpos}, readonly=True) # TODO: MD_OUT_WL or MD_IN_WL depending on affect self._metadata = { model.MD_FILTER_NAME: name, model.MD_OUT_WL: self._axes["band"].choices[curpos] }
def __init__(self, name, role, children, axes, rotation=0, scale=None, translation=None, **kwargs): """ children (dict str -> actuator): name to objective lens actuator axes (list of 2 strings): names of the axes for x and y scale (None tuple of 2 floats): scale factor from exported to original position rotation (float): rotation factor (in radians) translation (None or tuple of 2 floats): translation offset (in m) """ assert len(axes) == 2 if len(children) != 1: raise ValueError("ConvertStage needs 1 child") self._child = children.values()[0] self._axes_child = {"x": axes[0], "y": axes[1]} if scale is None: scale = (1, 1) if translation is None: translation = (0, 0) # TODO: range of axes could at least be updated with scale + translation axes_def = {"x": self._child.axes[axes[0]], "y": self._child.axes[axes[1]]} model.Actuator.__init__(self, name, role, axes=axes_def, **kwargs) self._metadata[model.MD_POS_COR] = translation self._metadata[model.MD_ROTATION_COR] = rotation self._metadata[model.MD_PIXEL_SIZE_COR] = scale self._updateConversion() # RO, as to modify it the client must use .moveRel() or .moveAbs() self.position = model.VigilantAttribute({"x": 0, "y": 0}, unit="m", readonly=True) # it's just a conversion from the child's position self._child.position.subscribe(self._updatePosition, init=True)
def __init__(self, name, role, parent, axes, ranges=None, **kwargs): assert len(axes) > 0 if ranges is None: ranges = {} axes_def = {} self._position = {} # Just z axis a = axes[0] # The maximum, obviously, is not 1 meter. We do not actually care # about the range since Tescan API will adjust the value set if the # required one is out of limits. rng = [0, 1] axes_def[a] = model.Axis(unit="m", range=rng) # start at the centre self._position[a] = parent._device.GetWD() * 1e-3 model.Actuator.__init__(self, name, role, parent=parent, axes=axes_def, **kwargs) # RO, as to modify it the client must use .moveRel() or .moveAbs() self.position = model.VigilantAttribute(self._applyInversionAbs( self._position), unit="m", readonly=True) # will take care of executing axis move asynchronously self._executor = CancellableThreadPoolExecutor( max_workers=1) # one task at a time
def __init__(self, name, role, children, axes, angle=0): """ children (dict str -> actuator): name to actuator with 2+ axes axes (list of string): names of the axes for x and y angle (float in degrees): angle of inclination (counter-clockwise) from virtual to physical """ assert len(axes) == 2 if len(children) != 1: raise ValueError("StageIncliner needs 1 child") self._child = children.values()[0] self._axes_child = {"x": axes[0], "y": axes[1]} self._angle = angle axes_def = { "x": self._child.axes[axes[0]], "y": self._child.axes[axes[1]] } model.Actuator.__init__(self, name, role, axes=axes_def) # RO, as to modify it the client must use .moveRel() or .moveAbs() self.position = model.VigilantAttribute({ "x": 0, "y": 0 }, unit="m", readonly=True) # it's just a conversion from the child's position self._child.position.subscribe(self._updatePosition, init=True)
def __init__(self, microscope, main_app): super(TimelapsePlugin, self).__init__(microscope, main_app) # Can only be used with a microscope if not microscope: return self.period = model.FloatContinuous(10, (1e-3, 10000), unit="s", setter=self._setPeriod) # TODO: prevent period < acquisition time of all streams self.numberOfAcquisitions = model.IntContinuous(100, (2, 100000)) self.semOnlyOnLast = model.BooleanVA(False) self.filename = model.StringVA("a.h5") self.expectedDuration = model.VigilantAttribute(1, unit="s", readonly=True) self.period.subscribe(self._update_exp_dur) self.numberOfAcquisitions.subscribe(self._update_exp_dur) # On SECOM/DELPHI, propose to only acquire the SEM at the end if microscope.role in ("secom", "delphi"): self.vaconf["semOnlyOnLast"][ "control_type"] = odemis.gui.CONTROL_CHECK self._dlg = None self.addMenu("Acquisition/Timelapse...\tCtrl+T", self.start) self._to_store = queue.Queue( ) # queue of tuples (str, [DataArray]) for saving data self._sthreads = [] # the saving threads self._exporter = None # dataio exporter to use
def __init__(self, name, role, wlp, children=None, **kwargs): """ wlp (list of floats): polynomial for conversion from distance from the center of the CCD to wavelength (in m): w = wlp[0] + wlp[1] * x + wlp[2] * x²... where w is the wavelength (in m), x is the position from the center (in m, negative are to the left), and p is the polynomial (in m, m^0, m^-1...). So, typically, a first order polynomial contains as first element the center wavelength, and as second element the light dispersion (in m/m) """ if kwargs.get("inverted", None): raise ValueError("Axis of spectrograph cannot be inverted") if not isinstance(wlp, list) or len(wlp) < 1: raise ValueError("wlp need to be a list of at least one float") # Note: it used to need a "ccd" child, but not anymore self._swVersion = "N/A (Odemis %s)" % odemis.__version__ self._hwVersion = name self._wlp = wlp pos = {"wavelength": self._wlp[0]} wla = model.Axis(range=(0, 2400e-9), unit="m") model.Actuator.__init__(self, name, role, axes={"wavelength": wla}, **kwargs) self.position = model.VigilantAttribute(pos, unit="m", readonly=True)
def __init__(self, microscope, main_app): super(AveragePlugin, self).__init__(microscope, main_app) # Can only be used with a microscope if not microscope: return # Check which stream the microscope supports main_data = self.main_app.main_data if not main_data.ebeam: return self.addMenu("Acquisition/Averaged frame...", self.start) dt = main_data.ebeam.dwellTime dtrg = (dt.range[0], min(dt.range[1], 1)) self.dwellTime = model.FloatContinuous(dt.value, range=dtrg, unit=dt.unit) self.scale = main_data.ebeam.scale # Trick to pass the component (ebeam to binning_1d_from_2d()) self.vaconf["scale"]["choices"] = ( lambda cp, va, cf: odemis.gui.conf.util.binning_1d_from_2d( self.main_app.main_data.ebeam, va, cf)) self.resolution = main_data.ebeam.resolution # Just for info self.accumulations = model.IntContinuous(10, (1, 10000)) self.filename = model.StringVA("a.h5") self.expectedDuration = model.VigilantAttribute(1, unit="s", readonly=True) self.dwellTime.subscribe(self._update_exp_dur) self.accumulations.subscribe(self._update_exp_dur) self.scale.subscribe(self._update_exp_dur)
def __init__(self, microscope, main_app): super(ZStackPlugin, self).__init__(microscope, main_app) # Can only be used with a microscope main_data = self.main_app.main_data if not microscope or main_data.focus is None: return self.focus = main_data.focus self._zrange = self.focus.axes['z'].range zunit = self.focus.axes['z'].unit self._old_pos = self.focus.position.value z = max(self._zrange[0], min(self._old_pos['z'], self._zrange[1])) self.zstart = model.FloatContinuous(z, range=self._zrange, unit=zunit) self.zstep = model.FloatContinuous(1e-6, range=(-1e-5, 1e-5), unit=zunit, setter=self._setZStep) self.numberOfAcquisitions = model.IntContinuous(3, (2, 999), setter=self._setNumberOfAcquisitions) self.filename = model.StringVA("a.h5") self.expectedDuration = model.VigilantAttribute(1, unit="s", readonly=True) self.zstep.subscribe(self._update_exp_dur) self.numberOfAcquisitions.subscribe(self._update_exp_dur) # Two acquisition order possible: # * for each Z, all the streams (aka intertwined): Z exactly the same for each stream # * for each stream, the whole Z stack: Might be faster (if filter wheel used for changing wavelength) self._streams_intertwined = True if main_data.light_filter and len(main_data.light_filter.axes["band"].choices) > 1: logging.info("Filter-wheel detected, Z-stack will be acquired stream-per-stream") self._streams_intertwined = False self._acq_streams = None # previously folded streams, for optimisation self._dlg = None self.addMenu("Acquisition/ZStack...\tCtrl+B", self.start)
def __init__(self, name, role, parent, **kwargs): """ axes (set of string): names of the axes """ fwd_info = parent.fwd_info() axes_def = { "z": model.Axis(unit=fwd_info["unit"], range=fwd_info["range"]), } model.Actuator.__init__(self, name, role, parent=parent, axes=axes_def, **kwargs) # will take care of executing axis move asynchronously self._executor = CancellableThreadPoolExecutor( max_workers=1) # one task at a time # RO, as to modify it the server must use .moveRel() or .moveAbs() self.position = model.VigilantAttribute({}, unit="m", readonly=True) self._updatePosition() # Refresh regularly the position self._pos_poll = util.RepeatingTimer(5, self._refreshPosition, "Position polling") self._pos_poll.start()
def __init__(self, name, role, axes, ranges=None, **kwargs): """ axes (set of string): names of the axes ranges (dict string -> float,float): min/max of the axis """ assert len(axes) > 0 if ranges is None: ranges = {} axes_def = {} self._position = {} init_speed = {} for a in axes: rng = ranges.get(a, (-0.1, 0.1)) axes_def[a] = model.Axis(unit="m", range=rng, speed=(0., 10.)) # start at the centre self._position[a] = (rng[0] + rng[1]) / 2 init_speed[a] = 1.0 # we are fast! model.Actuator.__init__(self, name, role, axes=axes_def, **kwargs) # Special file "stage.fail" => will cause simulation of hardware error if os.path.exists("stage.fail"): raise HwError("stage.fail file present, simulating error") self._executor = model.CancellableThreadPoolExecutor(max_workers=1) # RO, as to modify it the client must use .moveRel() or .moveAbs() self.position = model.VigilantAttribute({}, unit="m", readonly=True) self._updatePosition() self.speed = model.MultiSpeedVA(init_speed, (0., 10.), "m/s")
def __init__(self, name, role, parent, **kwargs): """ axes (set of string): names of the axes """ self.parent = parent axes_def = { # Ranges are from the documentation "z": model.Axis(unit="m", range=(FOCUS_RANGE[0] * 1e-3, FOCUS_RANGE[1] * 1e-3)), } model.Actuator.__init__(self, name, role, parent=parent, axes=axes_def, **kwargs) # will take care of executing axis move asynchronously self._executor = CancellableThreadPoolExecutor(max_workers=1) # one task at a time # RO, as to modify it the client must use .moveRel() or .moveAbs() self.position = model.VigilantAttribute({}, unit="m", readonly=True) self._updatePosition() # Refresh regularly the position self._pos_poll = util.RepeatingTimer(5, self._refreshPosition, "Focus position polling") self._pos_poll.start()
def __init__(self, name, coordinates, roc, asm, multibeam, descanner, detector): """ :param name: (str) Name of the region of acquisition (ROA). It is the name of the megafield (id) as stored on the external storage. :param coordinates: (float, float, float, float) left, top, right, bottom, Bounding box coordinates of the ROA in [m]. The coordinates are in the sample carrier coordinate system, which corresponds to the component with role='stage'. :param roc: (FastEMROC) Corresponding region of calibration (ROC). :param asm: (technolution.AcquisitionServer) The acquisition server module component. :param multibeam: (technolution.EBeamScanner) The multibeam scanner component of the acquisition server module. :param descanner: (technolution.MirrorDescanner) The mirror descanner component of the acquisition server module. :param detector: (technolution.MPPC) The detector object to be used for collecting the image data. """ self.name = model.StringVA(name) self.coordinates = model.TupleContinuous(coordinates, range=((-1, -1, -1, -1), (1, 1, 1, 1)), cls=(int, float), unit='m') self.roc = model.VigilantAttribute(roc) self._asm = asm self._multibeam = multibeam self._descanner = descanner self._detector = detector # List of tuples(int, int) containing the position indices of each field to be acquired. # Automatically updated when the coordinates change. self.field_indices = [] self.coordinates.subscribe(self.on_coordinates, init=True)
def __init__(self, microscope, main_app): super(ZStackPlugin, self).__init__(microscope, main_app) # Can only be used with a microscope main_data = self.main_app.main_data if not microscope or main_data.focus is None: return self.focus = main_data.focus self._zrange = self.focus.axes['z'].range zunit = self.focus.axes['z'].unit self.old_pos = self.focus.position.value self.zstart = model.FloatContinuous(self.old_pos['z'], range=self._zrange, unit=zunit) self.zstep = model.FloatContinuous(1e-6, range=(-1e-5, 1e-5), unit=zunit, setter=self._setZStep) self.numberofAcquisitions = model.IntContinuous( 3, (2, 999), setter=self._setNumberOfAcquisitions) self.filename = model.StringVA("a.h5") self.expectedDuration = model.VigilantAttribute(1, unit="s", readonly=True) self.zstep.subscribe(self._update_exp_dur) self.numberofAcquisitions.subscribe(self._update_exp_dur) self._acq_streams = None # previously folded streams, for optimisation self._dlg = None self.addMenu("Acquisition/ZStack...\tCtrl+B", self.start)
def __init__(self): fview = gmodel.MicroscopeView("fakeview") self.focussedView = omodel.VigilantAttribute(fview) self.main = Object() self.main.light = None self.main.ebeam = None self.main.debug = omodel.VigilantAttribute(fview) self.focussedView = omodel.VigilantAttribute(fview) self.light = None self.light_filter = None self.ccd = None self.sed = None self.ebeam = None self.tool = None self.subscribe = None
def __init__(self, name): model.Emitter.__init__(self, name, "fakeebeam", parent=None) self._shape = (2048, 2048) self.resolution = model.ResolutionVA((256, 256), [(1, 1), self._shape]) self.pixelSize = model.VigilantAttribute((1e-9, 1e-9), unit="m", readonly=True) self.magnification = model.FloatVA(1000.)
def __init__(self, name, role, port, axes, **kwargs): """ port (string): name of the serial port to connect to the controllers axes (dict string=> 2-tuple (0<=int<=15, 0<=int<=1)): the configuration of the network. for each axis name the controller address and channel Note that even if it's made of several controllers, each controller is _not_ seen as a child from the odemis model point of view. """ ser = PIRedStone.openSerialPort(port) # ser = FakePIRedStone.openSerialPort(port) # use FakePIRedStone for testing # Not to be mistaken with axes which is a simple public view self._axis_to_child = {} # axis name -> (PIRedStone, channel) axes_def = {} # axis name -> Axis # TODO also a rangesRel : min and max of a step position = {} speed = {} controllers = {} # address => PIRedStone for axis, (add, channel) in axes.items(): if not add in controllers: controllers[add] = PIRedStone(ser, add) # controllers[add] = FakePIRedStone(ser, add) # use FakePIRedStone for testing controller = controllers[add] self._axis_to_child[axis] = (controller, channel) position[axis] = controller.getPosition(channel) # TODO request also the ranges from the arguments? # For now we put very large one ad = model.Axis(canAbs=False, unit="m", range=(-1, 1), speed=(10e-6, 0.5)) # Just to make sure it doesn't go too fast speed[axis] = 0.1 # m/s axes_def[axis] = ad model.Actuator.__init__(self, name, role, axes=axes_def, **kwargs) # RO, as to modify it the client must use .moveRel() or .moveAbs() self.position = model.VigilantAttribute(position, unit="m", readonly=True) # min speed = don't be crazy slow. max speed from hardware spec self.speed = model.MultiSpeedVA(speed, range=[10e-6, 0.5], unit="m/s", setter=self._setSpeed) self._setSpeed(speed) # set HW and SW version self._swVersion = "%s (serial driver: %s)" % (odemis.__version__, driver.getSerialDriver(port)) hwversions = [] for axis, (ctrl, channel) in self._axis_to_child.items(): hwversions.append("'%s': %s" % (axis, ctrl.versionReport())) self._hwVersion = ", ".join(hwversions) # to acquire before sending anything on the serial port self.ser_access = threading.Lock() self._action_mgr = ActionManager(self) self._action_mgr.start()
def __init__(self, microscope, main_app): # Called when the plugin is loaed (ie, at GUI initialisation) super(Correlator2D, self).__init__(microscope, main_app) if not microscope or microscope.role not in ("sparc", "sparc2"): return try: self.ebeam = model.getComponent(role="e-beam") self.correlator = model.getComponent(role="time-correlator") self.sed = model.getComponent(role="se-detector") except LookupError: logging.debug("Hardware not found, cannot use the plugin") return # the SEM survey stream (will be updated when showing the window) self._survey_s = None # Create a stream for correlator spectral measurement self._correlator_s = CorrelatorScanStream("Correlator data", self.correlator, self.sed, self.ebeam, main_app.main_data.opm) # For reading the ROA and anchor ROI self._acqui_tab = main_app.main_data.getTabByName( "sparc_acqui").tab_data_model self.dwellTime = self._correlator_s.dwellTime self.pixelDuration = self._correlator_s.pixelDuration self.syncOffset = self._correlator_s.syncOffset self.syncDiv = self._correlator_s.syncDiv # The scanning positions are defined by ROI (as selected in the acquisition tab) + stepsize # Based on these values, the scanning resolution is computed self.roi = self._correlator_s.roi self.stepsize = self._correlator_s.stepsize self.cropvalue = self._correlator_s.cropvalue self.xres = model.IntVA(1, unit="px") self.yres = model.IntVA(1, unit="px") self.nDC = self._correlator_s.nDC self.filename = model.StringVA("a.h5") self.expectedDuration = model.VigilantAttribute(1, unit="s", readonly=True) # Update the expected duration when values change, depends both dwell time and # of pixels self.dwellTime.subscribe(self._update_exp_dur) self.stepsize.subscribe(self._update_exp_dur) self.nDC.subscribe(self._update_exp_dur) # subscribe to update X/Y res self.stepsize.subscribe(self._update_res) self.roi.subscribe(self._update_res) self.addMenu("Acquisition/CL time correlator scan...", self.start)
def __init__(self, name, role, children, axes, rotation=0, scale=None, translation=None): """ children (dict str -> actuator): name to objective lens actuator axes (list of 2 strings): names of the axes for x and y scale (None tuple of 2 floats): scale factor from exported to original position rotation (float): rotation factor (in radians) translation (None or tuple of 2 floats): translation offset (in m) """ assert len(axes) == 2 if len(children) != 1: raise ValueError("ConvertStage needs 1 child") self._child = children.values()[0] self._axes_child = {"x": axes[0], "y": axes[1]} if scale is None: scale = (1, 1) if translation is None: translation = (0, 0) # TODO: range of axes could at least be updated with scale + translation axes_def = { "x": self._child.axes[axes[0]], "y": self._child.axes[axes[1]] } model.Actuator.__init__(self, name, role, axes=axes_def) # Rotation * scaling for convert back/forth between exposed and child self._MtoChild = numpy.array( [[math.cos(rotation) * scale[0], -math.sin(rotation) * scale[0]], [math.sin(rotation) * scale[1], math.cos(rotation) * scale[1]]]) self._MfromChild = numpy.array( [[math.cos(-rotation) / scale[0], -math.sin(-rotation) / scale[1]], [math.sin(-rotation) / scale[0], math.cos(-rotation) / scale[1]]]) # Offset between origins of the coordinate systems self._O = numpy.array([translation[0], translation[1]], dtype=numpy.float) # RO, as to modify it the client must use .moveRel() or .moveAbs() self.position = model.VigilantAttribute({ "x": 0, "y": 0 }, unit="m", readonly=True) # it's just a conversion from the child's position self._child.position.subscribe(self._updatePosition, init=True)
def _init_projection_vas(self): """ Initialize the VAs related with image projection """ # DataArray or None: RGB projection of the raw data self.image = model.VigilantAttribute(None) # Don't call at init, so don't set metadata if default value self.tint.subscribe(self.onTint) self.intensityRange.subscribe(self._onIntensityRange)
def __init__(self, name, role, **kwargs): axes_def = {"z": model.Axis(unit="m", range=[-0.3, 0.3])} self._position = {"z": 0} model.Actuator.__init__(self, name, role, axes=axes_def, **kwargs) # RO, as to modify it the client must use .moveRel() or .moveAbs() self.position = model.VigilantAttribute( self._applyInversionAbs(self._position), unit="m", readonly=True)