예제 #1
0
    def __init__(self, configuration=None, **kwds):
        super().__init__(**kwds)
        self.buttons = []
        self.filter_fn = None
        self.parameters = params.StormXMLObject()
        self.scan_fn = None

        # Load UI
        self.ui = filterWheelUi.Ui_Dialog()
        self.ui.setupUi(self)

        # Create buttons.
        layout = QtWidgets.QHBoxLayout(self.ui.filtersGroupBox)
        layout.setContentsMargins(1, 1, 1, 1)
        layout.setSpacing(1)
        filter_names = configuration.get("filters").split(",")
        for name in filter_names:
            button = QtWidgets.QPushButton(name, self.ui.filtersGroupBox)
            button.setAutoExclusive(True)
            button.setCheckable(True)
            button.clicked.connect(self.handleClicked)
            layout.addWidget(button)
            self.buttons.append(button)

        # Set to minimum size & fix.
        self.adjustSize()
        self.setFixedSize(self.width(), self.height())

        self.parameters.add(
            params.ParameterSetString(description="Current filter",
                                      name="current_filter",
                                      value=filter_names[0],
                                      allowed=filter_names))
        self.setEnabled(False)
예제 #2
0
    def __init__(self, module_params = None, qt_settings = None, **kwds):
        super().__init__(**kwds)
        self.timing_functionality = None

        self.parameters = params.StormXMLObject()

        self.parameters.add(params.ParameterSetString(description = "Feed to use as the time base when filming",
                                                      name = "time_base",
                                                      value = "",
                                                      allowed = [""]))

        default_time_base = module_params.get("parameters").get("time_base")
        self.setAllowed([default_time_base])
        self.parameters.setv("time_base", default_time_base)
예제 #3
0
    def __init__(self, config=None, is_master=False, **kwds):
        kwds["config"] = config
        super().__init__(**kwds)

        # The camera configuration.
        self.camera_functionality = cameraFunctionality.CameraFunctionality(
            camera_name=self.camera_name,
            is_master=is_master,
            parameters=self.parameters)

        # Load the library and start the camera.
        self.camera = hcam.HamamatsuCameraMR(camera_id=config.get("camera_id"))

        # Dictionary of the Hamamatsu camera properties we'll support.
        self.hcam_props = {
            "binning": True,
            "defect_correct_mode": True,
            "exposure_time": True,
            "output_trigger_kind[0]": True,
            "output_trigger_polarity[0]": True,
            "readout_speed": True,
            "subarray_hpos": True,
            "subarray_hsize": True,
            "subarray_vpos": True,
            "subarray_vsize": True,
            "trigger_source": True
        }

        max_intensity = 2**self.camera.getPropertyValue("bit_per_channel")[0]
        self.parameters.setv("max_intensity", max_intensity)

        self.parameters.setv("exposure_time", 0.1)

        x_chip = self.camera.getPropertyValue("image_width")[0]
        y_chip = self.camera.getPropertyValue("image_height")[0]
        self.parameters.setv("x_chip", x_chip)
        self.parameters.setv("y_chip", y_chip)

        text_values = self.camera.sortedPropertyTextOptions("binning")
        self.parameters.add(
            params.ParameterSetString(description="Camera binning.",
                                      name="binning",
                                      value=text_values[0],
                                      allowed=text_values))

        text_values = self.camera.sortedPropertyTextOptions(
            "defect_correct_mode")
        self.parameters.add(
            params.ParameterSetString(description="Defect correction mode.",
                                      name="defect_correct_mode",
                                      value=text_values[0],
                                      allowed=text_values))

        # FIXME: Can't save this as the property name is not valid XML.
        text_values = self.camera.sortedPropertyTextOptions(
            "output_trigger_kind[0]")
        self.parameters.add(
            params.ParameterSetString(
                description="Camera 'fire' pin output kind.",
                name="output_trigger_kind[0]",
                value=text_values[1],
                allowed=text_values,
                is_saved=False))

        # FIXME: Can't save this as the property name is not valid XML.
        text_values = self.camera.sortedPropertyTextOptions(
            "output_trigger_polarity[0]")
        self.parameters.add(
            params.ParameterSetString(
                description="Camera 'fire' pin output polarity.",
                name="output_trigger_polarity[0]",
                value=text_values[1],
                allowed=text_values,
                is_saved=False))

        self.parameters.add(
            params.ParameterRangeInt(description="Read out speed",
                                     name="readout_speed",
                                     value=2,
                                     min_value=1,
                                     max_value=2))

        # These all need to multiples of 4.
        self.parameters.add(
            params.ParameterRangeInt(description="AOI X start",
                                     name="subarray_hpos",
                                     value=0,
                                     min_value=0,
                                     max_value=(x_chip - 1)))

        self.parameters.add(
            params.ParameterRangeInt(description="AOI Width",
                                     name="subarray_hsize",
                                     value=x_chip,
                                     min_value=4,
                                     max_value=x_chip))

        self.parameters.add(
            params.ParameterRangeInt(description="AOI Y start",
                                     name="subarray_vpos",
                                     value=0,
                                     min_value=0,
                                     max_value=(y_chip - 1)))

        self.parameters.add(
            params.ParameterRangeInt(description="AOI Height",
                                     name="subarray_vsize",
                                     value=y_chip,
                                     min_value=4,
                                     max_value=y_chip))

        text_values = self.camera.sortedPropertyTextOptions("trigger_source")
        self.parameters.add(
            params.ParameterSetString(description="Camera trigger source.",
                                      name="trigger_source",
                                      value=text_values[0],
                                      allowed=text_values))

        ## Disable editing of the HAL versions of these parameters.
        for param in [
                "x_bin", "x_end", "x_start", "y_end", "y_start", "y_bin"
        ]:
            self.parameters.getp(param).setMutable(False)

        self.newParameters(self.parameters, initialization=True)
예제 #4
0
    def __init__(self, w1=None, configuration=None, **kwds):
        super().__init__(**kwds)
        self.w1 = w1

        # assert max_speed is not None

        # Create dictionaries for the configuration of the
        # filter wheels and two dichroic mirror sets.
        self.filter_wheel_config = {}
        values = configuration.get("filter_wheel")
        filter_names = values.split(",")
        for pos, filter_name in enumerate(filter_names):
            self.filter_wheel_config[filter_name] = pos + 1

        self.dichroic_mirror_config = {}
        values = configuration.get("dichroic_mirror")
        dichroic_names = values.split(",")
        for pos, dichroic_name in enumerate(dichroic_names):
            self.dichroic_mirror_config[dichroic_name] = pos + 1

        # Create parameters
        self.parameters = params.StormXMLObject()

        self.parameters.add(
            params.ParameterSetBoolean(
                description="Bypass spinning disk for brightfield mode?",
                name="bright_field_bypass",
                value=False))

        self.parameters.add(
            params.ParameterSetBoolean(description="Spin the disk?",
                                       name="spin_disk",
                                       value=True))

        # Disk properties
        self.parameters.add(
            params.ParameterSetString(
                description="Disk pinhole size",
                name="disk",
                value="70-micron pinholes",
                allowed=["70-micron pinholes", "40-micron pinholes"]))

        # Dichroic mirror position
        values = sorted(self.dichroic_mirror_config.keys())
        self.parameters.add(
            params.ParameterSetString(
                description="Dichroic mirror position (1-5)",
                name="dichroic_mirror",
                value=values[0],
                allowed=values))

        # Filter wheel positions
        values = sorted(self.filter_wheel_config.keys())
        self.parameters.add(
            params.ParameterSetString(
                description="Camera 1 Filter Wheel Position (1-8)",
                name="filter_wheel",
                value=values[0],
                allowed=values))

        self.newParameters(self.parameters, initialization=True)
예제 #5
0
    def __init__(self, config = None, is_master = False, **kwds):
        """
        Create an Andor camera control object and initialize
        the camera.
        """
        kwds["config"] = config
        super().__init__(**kwds)
        self.is_master = is_master
        
        # The camera functionality.
        self.camera_functionality = cameraFunctionality.CameraFunctionality(camera_name = self.camera_name,
                                                                            have_temperature = True,
                                                                            is_master = is_master,
                                                                            parameters = self.parameters)
        
        # Load the library and start the camera.
        andor.loadSDK3DLL(config.get("andor_sdk"))
        self.camera = andor.SDK3Camera(config.get("camera_id"))

        # Dictionary of the Andor settings we'll use and their types.
        #
        # FIXME: Maybe the AndorSDK3 module should know the types?
        #
        self.andor_props = {"AOIBinning" : "enum",
                            "AOIHeight" : "int",
                            "AOILeft" : "int",
                            "AOITop" : "int",
                            "AOIWidth" : "int",
                            "CycleMode" : "enum",
                            "ExposureTime" : "float",
                            "FrameCount" : "int",
                            "FrameRate" : "float",
                            "FanSpeed" : "enum",
                            "IOInvert" : "bool",
                            "IOSelector" : "enum",
                            "SensorCooling" : "bool",
                            "SensorHeight" : "int",
                            "SensorTemperature" : "float",
                            "SensorWidth" : "int",
                            "SimplePreAmpGainControl" : "enum",
                            "TemperatureControl" : "enum",
                            "TemperatureStatus" : "enum",
                            "TriggerMode" : "enum"}
        
        self.camera.setProperty("CycleMode", self.andor_props["CycleMode"], "Continuous")

        # Set trigger mode.
        print(">", self.camera_name, "trigger mode set to", config.get("trigger_mode"))
        self.camera.setProperty("TriggerMode", self.andor_props["TriggerMode"], config.get("trigger_mode"))

        # Add Andor SDK3 specific parameters.
        #
        # FIXME: These parameter have different names but the same meaning as the
        #        parameters HAL defines. How to reconcile? It seems best to use
        #        these names as their meaning will be clearly to user.
        #
        max_intensity = 2**16
        self.parameters.setv("max_intensity", max_intensity)

        x_chip = self.camera.getProperty("SensorWidth", self.andor_props["SensorWidth"])
        y_chip = self.camera.getProperty("SensorHeight", self.andor_props["SensorHeight"])
        self.parameters.setv("x_chip", x_chip)
        self.parameters.setv("y_chip", y_chip)

        self.parameters.add(params.ParameterSetString(description = "AOI Binning",
                                                      name = "AOIBinning",
                                                      value = "1x1",
                                                      allowed = ["1x1", "2x2", "3x3", "4x4", "8x8"]))
        
        self.parameters.add(params.ParameterRangeInt(description = "AOI Width",
                                                     name = "AOIWidth",
                                                     value = x_chip,
                                                     min_value = 128,
                                                     max_value = x_chip))
        
        self.parameters.add(params.ParameterRangeInt(description = "AOI Height",
                                                     name = "AOIHeight",
                                                     value = y_chip,
                                                     min_value = 128,
                                                     max_value = y_chip))

        self.parameters.add(params.ParameterRangeInt(description = "AOI Left",
                                                     name = "AOILeft",
                                                     value = 1,
                                                     min_value = 1,
                                                     max_value = x_chip/2))

        self.parameters.add(params.ParameterRangeInt(description = "AOI Top",
                                                     name = "AOITop",
                                                     value = 1,
                                                     min_value = 1,
                                                     max_value = y_chip/2))

        self.parameters.add(params.ParameterSetString(description = "Fan Speed",
                                                      name = "FanSpeed",
                                                      value = "On",
                                                      allowed = ["On", "Off"]))

        self.parameters.add(params.ParameterSetBoolean(description = "Sensor cooling",
                                                       name = "SensorCooling",
                                                       value = True))

        self.parameters.add(params.ParameterSetString(description = "Pre-amp gain control",
                                                      name = "SimplePreAmpGainControl",
                                                      value = "16-bit (low noise & high well capacity)",
                                                      allowed = ["16-bit (low noise & high well capacity)", 
                                                                  "Something else.."]))

        self.parameters.add(params.ParameterRangeFloat(description = "Exposure time (seconds)", 
                                                       name = "ExposureTime", 
                                                       value = 0.1,
                                                       min_value = 0.0,
                                                       max_value = 10.0))

        # FIXME: We never actually set this. Maybe we can't?
        self.parameters.add(params.ParameterRangeFloat(description = "Target temperature", 
                                                       name = "temperature", 
                                                       value = -20.0,
                                                       min_value = -50.0,
                                                       max_value = 25.0))

        # Disable editing of the HAL versions of these parameters.
        for param in ["exposure_time", "x_bin", "x_end", "x_start", "y_end", "y_start", "y_bin"]:
            self.parameters.getp(param).setMutable(False)

        self.newParameters(self.parameters, initialization = True)
예제 #6
0
    def __init__(self, w1=None, configuration=None, **kwds):
        super().__init__(**kwds)
        self.w1 = w1

        # Query W1 for it's maximum speed.
        max_speed = self.w1.commandResponse("MS_MAX,?")
        assert max_speed is not None

        # Create dictionaries for the configuration of the
        # filter wheels and two dichroic mirror sets.
        self.filter_wheel_1_config = {}
        values = configuration.get("filter_wheel_1")
        filter_names = values.split(",")
        for pos, filter_name in enumerate(filter_names):
            self.filter_wheel_1_config[filter_name] = pos + 1

        self.filter_wheel_2_config = {}
        values = configuration.get("filter_wheel_2")
        filter_names = values.split(",")
        for pos, filter_name in enumerate(filter_names):
            self.filter_wheel_2_config[filter_name] = pos + 1

        self.dichroic_mirror_config = {}
        values = configuration.get("dichroic_mirror")
        dichroic_names = values.split(",")
        for pos, dichroic_name in enumerate(dichroic_names):
            self.dichroic_mirror_config[dichroic_name] = pos + 1

        self.camera_dichroic_config = {}
        values = configuration.get("camera_dichroic")
        camera_dichroic_names = values.split(",")
        for pos, camera_dichroic in enumerate(camera_dichroic_names):
            self.camera_dichroic_config[camera_dichroic] = pos + 1

        # Create parameters
        self.parameters = params.StormXMLObject()

        self.parameters.add(
            params.ParameterSetBoolean(
                description="Bypass spinning disk for brightfield mode?",
                name="bright_field_bypass",
                value=False))

        self.parameters.add(
            params.ParameterSetBoolean(description="Spin the disk?",
                                       name="spin_disk",
                                       value=True))

        # Disk properties
        self.parameters.add(
            params.ParameterSetString(
                description="Disk pinhole size",
                name="disk",
                value="50-micron pinholes",
                allowed=["50-micron pinholes", "25-micron pinholes"]))

        self.parameters.add(
            params.ParameterRangeInt(description="Disk speed (RPM)",
                                     name="disk_speed",
                                     value=max_speed,
                                     min_value=1,
                                     max_value=max_speed))

        # Dichroic mirror position
        values = sorted(self.dichroic_mirror_config.keys())
        self.parameters.add(
            params.ParameterSetString(description="Dichroic mirror position",
                                      name="dichroic_mirror",
                                      value=values[0],
                                      allowed=values))

        # Filter wheel positions
        values = sorted(self.filter_wheel_1_config.keys())
        self.parameters.add(
            params.ParameterSetString(
                description="Camera 1 Filter Wheel Position (1-10)",
                name="filter_wheel_pos1",
                value=values[0],
                allowed=values))

        values = sorted(self.filter_wheel_2_config.keys())
        self.parameters.add(
            params.ParameterSetString(
                description="Camera 2 Filter Wheel Position (1-10)",
                name="filter_wheel_pos2",
                value=values[0],
                allowed=values))

        # Camera dichroic positions
        values = sorted(self.camera_dichroic_config.keys())
        self.parameters.add(
            params.ParameterSetString(
                description="Camera dichroic mirror position (1-3)",
                name="camera_dichroic_mirror",
                value=values[0],
                allowed=values))

        # Aperature settings
        self.parameters.add(
            params.ParameterRangeInt(
                description="Aperture value (1-10; small to large)",
                name="aperture",
                value=10,
                min_value=1,
                max_value=10))

        self.newParameters(self.parameters, initialization=True)
예제 #7
0
    def createParameters(self, cam_fn, parameters_from_file):
        """
        Create (initial) parameters for the current feed.

        cam_fn - A camera / feed functionality object.
        parameters_from_file - The parameters that were read from the XML file.
        """
        # Check that we are not writing over something that already exists.
        if (self.parameters.has(self.getFeedName())):
            msg = "Display parameters for " + self.getFeedName() + " already exists."
            raise halExceptions.HalException(msg)

        # Create a sub-section for this camera / feed.
        p = self.parameters.addSubSection(self.getFeedName())

        # Add display specific parameters.
        p.add(params.ParameterFloat(name = "center_x",
                                    value = 0.0,
                                    is_mutable = False))

        p.add(params.ParameterFloat(name = "center_y",
                                    value = 0.0,
                                    is_mutable = False))
            
        p.add(params.ParameterSetString(description = "Color table",
                                        name = "colortable",
                                        value = self.color_tables.getColorTableNames()[0],
                                        allowed = self.color_tables.getColorTableNames()))
                        
        p.add(params.ParameterInt(description = "Display maximum",
                                  name = "display_max",
                                  value = 100))

        p.add(params.ParameterInt(description = "Display minimum",
                                  name = "display_min",
                                  value = 0))

        p.add(params.ParameterSetBoolean(name = "initialized",
                                         value = False,
                                         is_mutable = False))

        p.add(params.ParameterInt(name = "max_intensity",
                                  value = 100,
                                  is_mutable = False,
                                  is_saved = False))

        p.add(params.ParameterInt(name = "scale",
                                  value = 0,
                                  is_mutable = False))
            
        p.add(params.ParameterInt(description = "Frame to display when filming with a shutter sequence",
                                  name = "sync",
                                  value = 0))

        # Set parameters with default values from feed/camera functionality
        if cam_fn.hasParameter("colortable"):
            p.setv("colortable", cam_fn.getParameter("colortable"))
        else:
            p.setv("colortable", self.default_colortable)
        p.setv("display_max", cam_fn.getParameter("default_max"))
        p.setv("display_min", cam_fn.getParameter("default_min"))
        p.setv("max_intensity", cam_fn.getParameter("max_intensity"))

        # If they exist, update with the values that we loaded from a file.
        # Also, some parameters files will have 'extra' parameters, typically
        # sub-sections for the different feeds. We skip these here as this
        # will be handled when we change to the feed and call the
        # setCameraFunctionality() method.
        #
        if parameters_from_file is not None:
            for attr in parameters_from_file.getAttrs():
                if p.has(attr):
                    p.setv(attr, parameters_from_file.get(attr))
예제 #8
0
    def __init__(self, joystick=None, joystick_gains=None, **kwds):
        super().__init__(**kwds)

        self.button_timer = QtCore.QTimer(self)
        self.joystick = joystick
        self.joystick_gains = joystick_gains  # XML should be [25.0, 250.0, 2500.0]
        self.old_right_joystick = [0, 0]
        self.old_left_joystick = [0, 0]
        self.stage_functionality = None
        self.to_emit = False

        # The joystick parameters.
        self.parameters = params.StormXMLObject()

        self.parameters.add(
            params.ParameterInt(name="joystick_gain_index",
                                value=0,
                                is_mutable=False,
                                is_saved=False))

        self.parameters.add(
            params.ParameterInt(name="multiplier",
                                value=1,
                                is_mutable=False,
                                is_saved=False))

        self.parameters.add(
            params.ParameterRangeFloat(
                description="Step size in um for hat button press",
                name="hat_step",
                value=1.0,
                min_value=0.0,
                max_value=10.0))

        self.parameters.add(
            params.ParameterRangeFloat(
                description="X button multiplier for joystick and focus lock",
                name="joystick_multiplier_value",
                value=5.0,
                min_value=0.0,
                max_value=50.0))

        self.parameters.add(
            params.ParameterSetString(description="Response mode",
                                      name="joystick_mode",
                                      value="quadratic",
                                      allowed=["linear", "quadratic"]))

        self.parameters.add(
            params.ParameterSetFloat(description="Sign for x motion",
                                     name="joystick_signx",
                                     value=1.0,
                                     allowed=[-1.0, 1.0]))

        self.parameters.add(
            params.ParameterSetFloat(description="Sign for y motion",
                                     name="joystick_signy",
                                     value=1.0,
                                     allowed=[-1.0, 1.0]))

        self.parameters.add(
            params.ParameterRangeFloat(
                description="Focus lock step size in um",
                name="lockt_step",
                value=0.025,
                min_value=0.0,
                max_value=1.0))

        self.parameters.add(
            params.ParameterRangeFloat(
                description="Minimum joystick offset to be non-zero",
                name="min_offset",
                value=0.1,
                min_value=0.0,
                max_value=1.0))

        self.parameters.add(
            params.ParameterSetBoolean(description="Swap x and y axises",
                                       name="xy_swap",
                                       value=False))

        self.joystick.start(self.joystickHandler)

        self.button_timer.setInterval(100)
        self.button_timer.setSingleShot(True)
        self.button_timer.timeout.connect(self.buttonDownHandler)
예제 #9
0
    def __init__(self, parameters = None, **kwds):
        super().__init__(**kwds)
        self.parameters = parameters
        self.will_overwrite = False

        # Add default film parameters.        
        self.parameters.add(params.ParameterSetString(description = "Acquisition mode",
                                                      name = "acq_mode",
                                                      value = "fixed_length",
                                                      allowed = ["run_till_abort", "fixed_length"]))
        
        self.parameters.add(params.ParameterSetBoolean(description = "Automatically increment movie counter between movies",
                                                       name = "auto_increment",
                                                       value = True))
        
        self.parameters.add(params.ParameterSetBoolean(description = "Run shutters during the movie",
                                                       name = "auto_shutters",
                                                       value = True))
        
        self.parameters.add(params.ParameterString(description = "Current movie file name",
                                                   name = "filename",
                                                   value = "movie"))

        formats = imagewriters.availableFileFormats(parameters.get("test_mode", False))
        self.parameters.add(params.ParameterSetString(description = "Movie file type",
                                                      name = "filetype",
                                                      value = formats[0],
                                                      allowed = formats))
        
        self.parameters.add(params.ParameterRangeInt(description = "Movie length in frames",
                                                     name = "frames",
                                                     value = 10,
                                                     min_value = 1,
                                                     max_value = 1000000000))
        
        self.parameters.add(params.ParameterSetBoolean(description = "Sound bell at the end of long movies",
                                                       name = "want_bell",
                                                       value = True))

        # Initial UI configuration.
        self.ui = filmUi.Ui_GroupBox()
        self.ui.setupUi(self)
        
        for extname in self.parameters.getp("extension").getAllowed():
            self.ui.extensionComboBox.addItem(extname)
        
        for typename in self.parameters.getp("filetype").getAllowed():
            self.ui.filetypeComboBox.addItem(typename)

        self.ui.framesText.setText("")
        self.ui.sizeText.setText("")

        self.setDirectory(self.parameters.get("directory"))
        self.setShutters("NA")
        self.newParameters(self.parameters)
        self.updateFilenameLabel()

        # Connect signals
        self.ui.autoIncCheckBox.stateChanged.connect(self.handleAutoInc)
        self.ui.autoShuttersCheckBox.stateChanged.connect(self.handleAutoShutters)
        self.ui.extensionComboBox.currentIndexChanged.connect(self.handleExtension)
        self.ui.filenameEdit.textChanged.connect(self.handleFilename)
        self.ui.filetypeComboBox.currentIndexChanged.connect(self.handleFiletype)
        self.ui.indexSpinBox.valueChanged.connect(self.handleIndex)
        self.ui.lengthSpinBox.valueChanged.connect(self.handleLength)
        self.ui.liveModeCheckBox.stateChanged.connect(self.handleLiveMode)
        self.ui.modeComboBox.currentIndexChanged.connect(self.handleMode)
예제 #10
0
    def __init__(self, parameters, joystick, parent=None):
        QtCore.QObject.__init__(self, parent)
        halModule.HalModule.__init__(self, parent)

        self.button_timer = QtCore.QTimer(self)
        self.jstick = joystick
        self.old_right_joystick = [0, 0]
        self.old_left_joystick = [0, 0]
        self.to_emit = False

        # Add joystick specific parameters.
        js_params = parameters.addSubSection("joystick")
        js_params.add(
            "joystick_gain_index",
            params.ParameterInt("",
                                "joystick_gain_index",
                                0,
                                is_mutable=False,
                                is_saved=False))
        js_params.add(
            "multiplier",
            params.ParameterInt("",
                                "multiplier",
                                1,
                                is_mutable=False,
                                is_saved=False))
        js_params.add(
            "hat_step",
            params.ParameterRangeFloat("Step size in um for hat button press",
                                       "hat_step", 1.0, 0.0, 10.0))
        js_params.add("joystick_gain", [25.0, 250.0, 2500.0])
        js_params.add(
            "joystick_multiplier_value",
            params.ParameterRangeFloat(
                "X button multiplier for joystick and focus lock",
                "joystick_multiplier_value", 5.0, 0.0, 50.0))
        js_params.add(
            "joystick_mode",
            params.ParameterSetString("Response mode", "joystick_mode",
                                      "quadratic", ["linear", "quadratic"]))
        js_params.add(
            "joystick_signx",
            params.ParameterSetFloat("Sign for x motion", "joystick_signx",
                                     1.0, [-1.0, 1.0]))
        js_params.add(
            "joystick_signy",
            params.ParameterSetFloat("Sign for y motion", "joystick_signy",
                                     1.0, [-1.0, 1.0]))
        js_params.add(
            "lockt_step",
            params.ParameterRangeFloat("Focus lock step size in um",
                                       "lockt_step", 0.025, 0.0, 1.0))
        js_params.add(
            "min_offset",
            params.ParameterRangeFloat(
                "Minimum joystick offset to be non-zero", "min_offset", 0.1,
                0.0, 1.0))
        js_params.add(
            "xy_swap",
            params.ParameterSetBoolean("Swap x and y axises", "xy_swap",
                                       False))
        self.parameters = js_params

        self.jstick.start(self.joystickHandler)

        self.button_timer.setInterval(100)
        self.button_timer.setSingleShot(True)
        self.button_timer.timeout.connect(self.buttonDownHandler)