def exposure(self, exposure: Q_): self.logger.info(f'Setting exposure to {exposure}') try: if not isinstance(exposure, Q_): exposure = Q_(exposure) self._driver.ExposureTime.SetValue(exposure.m_as('us')) exposure = float(self._driver.ExposureTime.ToString()) * Q_('us') self.config.upgrade({'exposure': exposure}) except _genicam.TimeoutException: self.logger.error(f'Timed out setting the exposure to {exposure}')
def do_scan(self): """ Does the scan considering that everything else was already set up. """ scan = self.scan laser = self.devices[scan['laser']['name']] axis = scan['axis'] approx_time_to_scan = (laser.params['stop_wavelength']-laser.params['start_wavelength'])/laser.params['wavelength_speed'] self.logger.info('Total number of devices to scan: {}'.format(len(axis))) self.logger.info('Approximate time to do a laser scan: {}'.format(approx_time_to_scan)) if len(axis) != 1: self.logger.warning('Trying to do a scan of {} dimensions. The program only supports 1 dimenstion'.format(len(axis))) raise Warning('Wrong number of axis') dev_to_scan = list(axis.keys())[-1] # Get the name of the device self.logger.info('Device to scan: {}'.format(dev_to_scan)) actuator_to_scan = list(axis[dev_to_scan].keys())[-1] self.logger.info('Actuator to scan: {}'.format(actuator_to_scan)) range = axis[dev_to_scan][actuator_to_scan]['rage'] self.logger.debug('Range to scan: {}'.format(range)) # Scan the laser and the values of the given device if dev_to_scan != 'time': start = Q_(range[0]) stop = Q_(range[1]) step = Q_(range[2]) units = start.u num_points_dev = ((stop-start)/step).to('') + 1 # This is to include also the last point else: start = 1 stop = range[1] num_points_dev = stop for value in np.linspace(start, stop, num_points_dev): if dev_to_scan != 'time': self.devices[dev_to_scan]['actuators'][actuator_to_scan].value = value * units self.logger.debug('Set {} to {}'.format(actuator_to_scan, value)) laser.driver.execute_sweep() self.logger.info('Executing laser sweep') sleep(0.1) while laser.driver.sweep_condition != 'Stop': sleep(approx_time_to_scan.m/Config.Laser.number_checks_per_scan) for device in self.scan['detectors']: dev = self.devices[device]['dev'] daq_driver = dev.driver daq_driver.stop_task() daq_driver.clear_task()
def apply_value(self, actuator, value): """ Sets the output of the NI card. For the time being it sets a DC constant value; this has to be expanded to other types of actuators, for example a digital output. .. todo:: Make this method work with actuators of different types than analog .. warning:: This method is not intended for making ramps or generating a continuous output; it is just a handy way of changing the value of a particular port. :param actuator: specifies the actuator on which to act. :param value: The value to be set """ port = actuator.properties['port'] # First let's check that the actuator is an analog channel if actuator.properties['type'] == 'analog': port = "Dev%s/ao%s" % (self.daq_num, port) calibration = actuator.calibration # Convert value to volts: output_volts = from_units_to_volts(value, calibration) min_value = Q_(actuator.properties['limits']['min']) max_value = Q_(actuator.properties['limits']['max']) # Convert values to volts: # The NI card needs to specify min and max voltages; the actuator itself should check that the voltages # are within limits before even arriving here. In any case, as a safe, the NI card will never output a value # beyond the limits. min_V = from_units_to_volts(min_value, calibration) max_V = from_units_to_volts(max_value, calibration) autostart = nidaq.bool32(True) timeout = Config.NI.Output.Analog.timeout self.logger.debug('Actuator: {}, MIN: {}, MAX: {}, Value: {}'.format(actuator.name, min_V, max_V, output_volts)) t = nidaq.Task() t.CreateAOVoltageChan(port, None, min_V, max_V, nidaq.DAQmx_Val_Volts, None) t.WriteAnalogScalarF64(autostart, timeout, output_volts, None) t.StopTask() t.ClearTask() self.logger.info('Changed the value of {} to {}'.format(actuator.name, value))
def exposure(self) -> Q_: """ The exposure of the camera, defined in units of time """ if self.config['exposure'] is not None: return self.config['exposure'] try: exposure = float(self._driver.ExposureTime.ToString()) * Q_('us') return exposure except _genicam.TimeoutException: self.logger.error('Timeout getting the exposure') return self.config['exposure']
def __set__(self, instance, value): if self.units: if isinstance(value, Q_): value = value.to(self.units) elif isinstance(value, str): value = Q_(value).to(self.units) elif isinstance(value, Number): value = value * self.units else: raise Exception(f'Cant set {self.name} to {value}') self._value = value
def analog_output_dc(self, conditions): """ Sets the analog output of the NI card. For the time being is thought as a DC constant value. :param dict conditions: specifies DEV and Value :return: """ dev = conditions['dev'] port = "Dev%s/ao%s" % (self.daq_num, dev.properties['port']) units = Q_(dev.properties['calibration']['units']) min_value = Q_(dev.properties['limits']['min']).to(units) max_value = Q_(dev.properties['limits']['max']).to(units) # Convert values to volts: value = conditions['value'].to(units) V = self.from_units_to_volts(value, dev) min_V = self.from_units_to_volts(min_value, dev) max_V = self.from_units_to_volts(max_value, dev) t = nidaq.Task() t.CreateAOVoltageChan(port, None, min_V, max_V, nidaq.DAQmx_Val_Volts, None) t.WriteAnalogScalarF64(nidaq.bool32(True), 0, V, None) t.StopTask() t.ClearTask()
def read_value(self, sensor): """ Reads the value of a sensor. .. todo:: Make this method work with sensors other than analog inputs. :param sensor: the sensor to read. :return: The value read, with units if appropriate. """ port = sensor.properties['port'] if sensor.properties['type'] == 'analog': port = "Dev%s/ai%s" % (self.daq_num, port) calibration = sensor.properties['calibration'] min_value = Q_(sensor.properties['limits']['min']) max_value = Q_(sensor.properties['limits']['max']) min_V = from_units_to_volts(min_value, calibration) max_V = from_units_to_volts(max_value, calibration) freq = Config.NI.Input.Analog.freq trigger = Config.NI.Input.Analog.trigger trigger_edge = Config.NI.Input.Analog.trigger_edge measure_mode = Config.NI.Input.Analog.measure_mode num_points = Config.NI.Input.Analog.num_points cont_finite = Config.NI.Input.Analog.cont_finite t = nidaq.Task() t.CreateAIVoltageChan(port, None, measure_mode, min_V, max_V, nidaq.DAQmx_Val_Volts, None) t.CfgSampClkTiming(trigger, freq, trigger_edge, cont_finite, num_points) t.StartTask() time.sleep(num_points*freq) timeout = Config.NI.Input.Analog.read_timeout read = nidaq.int32() data = np.zeros((num_points,), dtype=np.float64) t.ReadAnalogF64(num_points, timeout, nidaq.DAQmx_Val_GroupByChannel, data, num_points, nidaq.byref(read), None) value = np.mean(data) return from_volts_to_units(value, calibration)
def __init__(self, units=None, ui_class=None): self._value = None self.units = None if units: if isinstance(units, Q_): self.units = units else: try: self.units = Q_(units) except UndefinedUnitError: self.units = None self.ui_class = ui_class
def value(self, value): if self._device is None: err_str = "Trying to update a value of {} before connecting it to a device".format( self.name) logger.error(err_str) raise Exception(err_str) if 'limits' in self.properties: if value > Q_(self.properties['limits']['max']) or value < Q_( self.properties['limits']['min']): wrn_msg = 'Trying to set {} to {}, while limits are ({}, {})'.format( self.name, value, self.properties['limits']['min'], self.properties['limits']['max']) logger.warning(wrn_msg) raise Warning(wrn_msg) return try: self._device.apply_value( self, value ) # self has to be passed as an explicit argument since the method is # expecting an actuator as argument. except Exception as e: logger.error("Failed to apply {} to {}: {}".format( value, self.name, e)) raise e
def from_units_to_volts(self, value, dev): """ Converts a value from specific actuator units into volts to pass to a DAQ. :param value: The output value :param dev: The calibration of the device, including units. :type value: Quantity :type dev: dict. """ units = Q_(dev.properties['calibration']['units']) slope = dev.properties['calibration']['slope'] * units offset = dev.properties['calibration']['offset'] * units value = value.to(units) value = value.m slope = slope.m offset = offset.m return (value - offset) / slope
def buffer_size(self, value): value = Q_(value) self.logger.info(f'{self} - Setting buffer size to {value}') self._buffer_size = value
def get_exposure(self) -> Q_: self.exposure = float(self.camera.ExposureTime.ToString()) * Q_('us') return self.exposure
def configure(self, properties: dict): """ Configure the camera based on a dictionary of properties. .. deprecated:: 0.3.0 By implementing features, this method is no longer required """ self.logger.info('Updating config') update_cam = False update_roi = False update_exposure = False update_binning = False update_gain = False for k, new_prop in properties.items(): self.logger.debug('Updating {} to {}'.format(k, new_prop)) update_cam = False if k in self.config: old_prop = self.config[k] if new_prop != old_prop: update_cam = True else: update_cam = True if update_cam: if k in ['roi_x1', 'roi_x2', 'roi_y1', 'roi_y2']: update_roi = True elif k == 'exposure_time': update_exposure = True elif k in ['binning_x', 'binning_y']: update_binning = True elif k == 'gain': update_gain = True if update_cam: self.logger.info('There are things to update in the new config') if update_roi: X = sorted([properties['roi_x1'], properties['roi_x2']]) Y = sorted([properties['roi_y1'], properties['roi_y2']]) self.logger.info(f'Updating ROI {X}, {Y}') self.set_ROI(X, Y) self.config.update({ 'roi_x1': X[0], 'roi_x2': X[1], 'roi_y1': Y[0], 'roi_y2': Y[1] }) if update_exposure: exposure = properties['exposure_time'] self.logger.info(f'Updating exposure to {exposure}') if isinstance(exposure, str): exposure = Q_(exposure) new_exp = self.set_exposure(exposure) self.config['exposure_time'] = new_exp if update_binning: self.logger.info('Updating binning') self.set_binning(properties['binning_x'], properties['binning_y']) self.config.update({ 'binning_x': properties['binning_x'], 'binning_y': properties['binning_y'] }) if update_gain: self.logger.info(f'Updating gain to {properties["gain"]}') self.set_gain(properties['gain'])
self.camera.Close() def __str__(self): if self.friendly_name: return self.friendly_name return "Basler Camera" if __name__ == '__main__': from time import sleep logger.setLevel(logging.DEBUG) ch = logging.StreamHandler() ch.setLevel(logging.DEBUG) formatter = logging.Formatter( '%(asctime)s - %(name)s - %(levelname)s - %(message)s') ch.setFormatter(formatter) logger.addHandler(ch) logger.info('Starting Basler') basler = Camera(0) basler.initialize() basler.set_acquisition_mode(basler.MODE_SINGLE_SHOT) basler.set_exposure(Q_('.02s')) basler.trigger_camera() print(len(basler.read_camera())) basler.set_acquisition_mode(basler.MODE_CONTINUOUS) basler.trigger_camera() sleep(1) imgs = basler.read_camera() print(len(imgs))
from time import sleep from experimentor import Q_ from experimentor.config import settings from experimentor.core.publisher import Publisher, Listener from experimentor.core.subscriber import Subscriber from experimentor.models.cameras.basler import BaslerCamera cam = BaslerCamera('da') cam.initialize() cam.clear_ROI() cam.set_acquisition_mode(cam.MODE_CONTINUOUS) cam.set_ROI((1, 100), (1, 100)) cam.set_exposure(Q_('10ms')) publisher = Publisher(settings.GENERAL_STOP_EVENT) publisher.start() listener = Listener() def func(frame): print(len(frame)) subscriber = Subscriber(func, 'frame') subscriber.start() sleep(2) cam.trigger_camera()
from time import time from experimentor import Q_ from experimentor.models.devices.cameras.basler.basler import BaslerCamera cam = BaslerCamera('p') cam.initialize() cam.exposure = Q_('10ms') t0 = time() i = 0 while True: try: cam.trigger_camera() ans = cam.read_camera()[0] print(f'Acquired {i} frames, {i/(time()-t0)} fps', end='\r') except KeyboardInterrupt: break cam.finalize()
def set_exposure(self, exposure: Q_) -> Q_: self.camera.ExposureTime.SetValue(exposure.m_as('us')) self.exposure = exposure return self.get_exposure()