Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add Thorlabs DotNetAPI #386

Open
wants to merge 35 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
42aae2c
add Thorlabs DotNetAPI
Nov 27, 2024
95aecdb
updated readme, added template
Nov 27, 2024
a56cc02
Update README.md - typo
DCEM Nov 29, 2024
8684ee1
fix model variable
Dec 6, 2024
44339ce
correct error in Template
DCEM Dec 13, 2024
0967fef
Update docstring Thorlabs_Template_DotNet.py
DCEM Dec 13, 2024
357648c
cast serial_number as a string
Dec 18, 2024
c292373
remove dll_directory from kwars
Dec 18, 2024
866d17f
update comments
Dec 18, 2024
e2db70e
update/corect destructor behaviour
Dec 19, 2024
7408bc3
dont use validators if min >= max (true for simulation)
Dec 19, 2024
2e61735
Update Template file
Dec 19, 2024
2db86f4
update Template file
Dec 20, 2024
a0ba59b
rework ThorlabsMixin with reflection-based enum handling and optional…
Dec 26, 2024
0c3669b
correct DotNetDecimal conversion
Dec 27, 2024
2a9c80c
update ThorlabsObjectWrapper to handle decimal_as_float
Dec 27, 2024
45a01a1
add KLSnnn
Dec 27, 2024
3454341
update GenericMotorCLI to handle int based enums
Dec 27, 2024
41b27d1
add MFF10x
Dec 20, 2024
f8fa484
add MFF002 to knownmodels
Dec 20, 2024
1d406e7
add KDC101
Nov 27, 2024
4512879
updated Thorlabs_K10CR1_DotNet.py
Nov 27, 2024
ebdc5af
apply CageRotator typo patch
Dec 6, 2024
8210c78
fix Thorlabs uppercase L type in Namespace
Dec 6, 2024
7de5c08
corect device name and update comments
Dec 19, 2024
4a836f5
correct name and location of IntegratedStepperMotorCLI classes
Dec 20, 2024
3506862
update K10CR1 to new class location
Dec 20, 2024
f8b80a9
update GenericMotorCLI ControlParameters to use int based enums
Dec 27, 2024
adda5c2
update GenericMotorCLI_AdvancedMotor DCStatus
Dec 28, 2024
0bcdfed
Update Template File
Dec 28, 2024
9509456
update _compute_move_time_ms
Dec 28, 2024
67b512c
add TDC001
Dec 28, 2024
930d055
Merge branch 'add-MFF10x' into add-Thorlabs-DotNetAPI
Dec 28, 2024
b8486fe
Merge branch 'add-KLSnnn' into add-Thorlabs-DotNetAPI
Dec 28, 2024
1af668e
Merge branch 'add_KDC101' into add-Thorlabs-DotNetAPI
Dec 28, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
179 changes: 179 additions & 0 deletions src/qcodes_contrib_drivers/drivers/Thorlabs/Thorlabs_BSCxxx_DotNet.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
import logging
from time import sleep
from typing import Optional, List

from qcodes.instrument.channel import InstrumentChannel
from .private.DotNetAPI.DeviceManagerCLI import IGenericRackDevice
from .private.DotNetAPI.GenericMotorCLI_AdvancedMotor import GenericAdvancedMotorCLI
from .private.DotNetAPI.qcodes_thorlabs_integration import ThorlabsQcodesInstrument, ThorlabsMixin


log = logging.getLogger(__name__)

class ThorlabsBSCxxx(IGenericRackDevice, ThorlabsQcodesInstrument):
"""
Instrument driver for the Thorlabs Benchtop Stepper Motor series BSCxxx.

This driver interfaces with a Thorlabs motor using the .NET API, providing
control over the motor's functions. It handles the initialization and
management of the motor and its channels.

This class integrates the Thorlabs device, using the .NET API.
For further .NET API details please refer to:
.private/DotNetAPI/README.md

Args:
name: Name of the instrument.
serial_number: The serial number of the Thorlabs device.
actuator_names: List of actuator names, size should match channel number.
startup_mode_values: List of startup_mode_values, size should match channel number.
startup_mode_value: .Net Enum value to be stored in '_startup_mode' and used as
'startupSettingsMode' in 'LoadMotorConfiguration'
Valid startup modes:
UseDeviceSettings: Use settings from device
UseFileSettings: Use settings stored locally
UseConfiguredSettings: Use one of the above according to
choice in Kinesis Software
dll_directory: The directory where the DLL files are located.
simulation: Flag to determine if the device is in simulation mode.
polling_rate_ms: Polling rate in milliseconds for the device.

Raises:
ValueError: If the model is not recognized as a known model.
"""
def __init__(self,
name: str,
serial_number: str,
actuator_names: Optional[List[str]] = None,
startup_mode_values: List[str] = ['UseConfiguredSettings', 'UseConfiguredSettings', 'UseConfiguredSettings'],
simulation: Optional[bool] = False,
polling_rate_ms: int = 250,
dll_directory: Optional[str] = None,
**kwargs
):
super().__init__(
name, # Instrument (Qcodes)
serial_number=serial_number, # IGenericCoreDeviceCLI
simulation=simulation, # ThorlabsQcodesInstrument
dll_directory=dll_directory, # ThorlabsDLLMixin
**kwargs)

# Initialize channels
for channel_number in range(1, self.channel_count() + 1):
if actuator_names is not None:
actuator_name = actuator_names[channel_number - 1]
else:
actuator_name = None

startup_mode_value = startup_mode_values[channel_number - 1]

channel = ThorlabsBSCxxxChannel(
self,
f"channel{channel_number}",
self._api_interface.GetChannel(channel_number),
actuator_name,
startup_mode_value,
polling_rate_ms
)
self.add_submodule(f"channel{channel_number}", channel)

self.connect_message()

if '(Simulated)' not in self.model():
self.snapshot(True)

def _import_device_dll(self):
"""Import the device-specific DLLs and classes from the .NET API."""
self._add_dll('Thorlabs.MotionControl.GenericMotorCLI.dll')
self._add_dll('Thorlabs.MotionControl.Benchtop.StepperMotorCLI.dll')
self._import_dll_class('Thorlabs.MotionControl.Benchtop.StepperMotorCLI', 'BenchtopStepperMotor')

def _get_api_interface_from_dll(self, serial_number: str):
"""Retrieve the API interface for the Thorlabs device using its serial number."""
return self._dll.BenchtopStepperMotor.CreateBenchtopStepperMotor(serial_number)

def _post_connection(self):
"""
Will run after after establishing a connection, updating 'get_idn'
and adding parameters 'model', 'serial_number' and 'firmware_version'.
"""
knownmodels = [
'BSC203'#,
#'BSC203 (Simulated)'
]
if self.model() not in knownmodels:
raise ValueError(f"'{self.model()}' is an unknown model.")


class ThorlabsBSCxxxChannel(GenericAdvancedMotorCLI, ThorlabsMixin, InstrumentChannel):
"""
Channel class for a single channel of the Thorlabs BSCxxx Benchtop Stepper Motor.

Each channel represents an individual motor and provides methods to interact with
it, such as initialization and setting parameters, through the .NET API.

This class integrates the Thorlabs channel, using the .NET API.
For further .NET API details please refer to:
.private/DotNetAPI/README.md

Args:
parent: The parent Qcodes Instrument or Station.
name: Name to identify this instance.
api_interface: The API interface for the channel.
actuator_name: The name of the actuator.
startup_mode_value: .Net Enum value to be stored in '_startup_mode' and used as
'startupSettingsMode' in 'LoadMotorConfiguration'
Valid startup modes:
UseDeviceSettings: Use settings from device
UseFileSettings: Use settings stored locally
UseConfiguredSettings: Use one of the above according to
choice in Kinesis Software
polling_rate_ms: Polling rate in milliseconds for the channel.
**kwargs: Additional keyword arguments.

Raises:
RuntimeError: If unable to connect to the channel.
"""

def __init__(self, parent: ThorlabsBSCxxx,
name: str,
api_interface,
actuator_name: str,
startup_mode_value: str,
polling_rate_ms: int = 250,
**kwargs):
self._actuator_name = actuator_name

super().__init__(
parent,
name,
api_interface=api_interface,
startup_mode_value=startup_mode_value,
polling_rate_ms=polling_rate_ms,
**kwargs)

def _post_enable(self):
"""
This method can be overwritten by a subclass.
Will run after polling has started and the device/channel is enabled.
"""
# Load any configuration settings needed by the device/channel
if self.parent.model() == 'BSC203':
serial = self._api_interface.DeviceID.strip()
else:
serial = self.parent.serial_number()

mode = self._startup_mode

self._configuration = (
self._api_interface.LoadMotorConfiguration(serial, mode))

# self._settings = self._api_interface.MotorDeviceSettings
# self._api_interface.GetSettings(self._settings)

self._configuration.DeviceSettingsName = self._actuator_name
self._configuration.UpdateCurrentConfiguration()
# self._api_interface.SetSettings(self._settings, True, False)

self._api_interface.SetSettings(self._api_interface.MotorDeviceSettings, True, False)
sleep(0.5)
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import logging
from typing import Optional
# from time import sleep

from .private.DotNetAPI.IntegratedStepperMotorsCLI import CageRotator
from .private.DotNetAPI.qcodes_thorlabs_integration import ThorlabsQcodesInstrument

log = logging.getLogger(__name__)

class ThorlabsK10CR1(CageRotator, ThorlabsQcodesInstrument):
"""
Driver for interfacing with the Thorlabs K10CR1 Motorised Rotation Mount
via the QCoDeS framework and the .NET API.

This class allows for control and management of the K10CR1.

This class integrates the Thorlabs device, using the .NET API.
For further .NET API details please refer to:
.private/DotNetAPI/README.md

Args:
name (str): Name of the instrument.
serial_number (str): The serial number of the Thorlabs device.
startup_mode_value: .Net Enum value to be stored in '_startup_mode' and used as
'startupSettingsMode' in 'LoadMotorConfiguration'
Valid startup modes:
UseDeviceSettings: Use settings from device
UseFileSettings: Use settings stored locally
UseConfiguredSettings: Use one of the above according to chooice in
Kinesis Sortware
simulation (Optional[bool]): Flag to determine if the device is in simulation mode.
polling_rate_ms (int): Polling rate in milliseconds for the device.
dll_directory (Optional[str]): The directory where the DLL files are located.
Raises:
ValueError: If the model is not recognized as a known model.
"""
def __init__(
self,
name: str,
serial_number: str,
startup_mode_value: str = 'UseDeviceSettings',
simulation: Optional[bool] = False,
polling_rate_ms: int = 250,
dll_directory: Optional[str] = None,
**kwargs
):

super().__init__(
name, # Instrument (Qcodes
serial_number=serial_number, # IGenericCoreDeviceCLI
startup_mode_value=startup_mode_value, # IGenericDeviceCLI
simulation=simulation, # ThorlabsQcodesInstrument
polling_rate_ms=polling_rate_ms, # IGenericDeviceCLI
dll_directory=dll_directory, # ThorlabsDLLMixin
**kwargs)

if '(Simulated)' not in self.model():
self.snapshot(True)

self.connect_message()

def _import_device_dll(self):
"""Import the device-specific DLLs and classes from the .NET API."""
self._add_dll('Thorlabs.MotionControl.GenericMotorCLI.dll')
self._add_dll('Thorlabs.MotionControl.IntegratedStepperMotorsCLI.dll')
self._import_dll_class('Thorlabs.MotionControl.IntegratedStepperMotorsCLI', 'CageRotator')

def _get_api_interface_from_dll(self, serial_number: str):
"""Retrieve the API interface for the Thorlabs device using its serial number."""
return self._dll.CageRotator.CreateCageRotator(serial_number)

def _post_connection(self):
"""
Will run after after establishing a connection, updating 'get_idn'
and adding parameters 'model', 'serial_number' and 'firmware_version'.
"""
knownmodels = [
'K10CR1'#,
#'K10CR1 (Simulated)'
]
if self.model() not in knownmodels:
raise ValueError(f"'{self.model()}' is an unknown model.")

def _post_enable(self):
"""
Will run after polling has started and the device/channel is enabled.
"""
# Load any configuration settings needed by the device/channel
serial = self._serial_number
mode = self._startup_mode
self._api_interface.LoadMotorConfiguration(serial, mode)
self._configuration = self._api_interface.LoadMotorConfiguration(serial)
104 changes: 104 additions & 0 deletions src/qcodes_contrib_drivers/drivers/Thorlabs/Thorlabs_KDC101_DotNet.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import logging
from time import sleep
from typing import Optional

from .private.DotNetAPI.GenericMotorCLI_ControlParameters import IDCPIDParameters
from .private.DotNetAPI.DeviceManagerCLI import IDeviceScanning
from .private.DotNetAPI.GenericMotorCLI_KCubeMotor import GenericKCubeMotorCLI
from .private.DotNetAPI.qcodes_thorlabs_integration import ThorlabsQcodesInstrument

log = logging.getLogger(__name__)

class ThorlabsKDC101(IDCPIDParameters, IDeviceScanning, GenericKCubeMotorCLI, ThorlabsQcodesInstrument):
"""
Driver for interfacing with the Thorlabs KDC101 K-Cube Brushed DC Servo Motor
Controller via the QCoDeS framework and the .NET API.

This class allows for control and management of the KDC101.

This class integrates the Thorlabs device, using the .NET API.
For further .NET API details please refer to:
.private/DotNetAPI/README.md

Args:
name (str): Name of the instrument.
serial_number (str): The serial number of the Thorlabs device.
actuator_name: The name of the actuator to be used.
startup_mode_value: .Net Enum value to be stored in '_startup_mode' and used as
'startupSettingsMode' in 'LoadMotorConfiguration'
Valid startup modes:
UseDeviceSettings: Use settings from device
UseFileSettings: Use settings stored locally
UseConfiguredSettings: Use one of the above according to chooice in
Kinesis Sortware
simulation (Optional[bool]): Flag to determine if the device is in simulation mode.
polling_rate_ms (int): Polling rate in milliseconds for the device.
dll_directory (Optional[str]): The directory where the DLL files are located.
Raises:
ValueError: If the model is not recognized as a known model.
"""
def __init__(
self,
name: str,
serial_number: str,
actuator_name: Optional[str] = None,
startup_mode_value: str = 'UseConfiguredSettings',
simulation: Optional[bool] = False,
polling_rate_ms: int = 250,
dll_directory: Optional[str] = None,
**kwargs
):
self._actuator_name = actuator_name

super().__init__(
name, # Instrument (Qcodes
serial_number=serial_number, # IGenericCoreDeviceCLI
startup_mode_value=startup_mode_value, # IGenericDeviceCLI
simulation=simulation, # ThorlabsQcodesInstrument
polling_rate_ms=polling_rate_ms, # IGenericDeviceCLI
dll_directory=dll_directory, # ThorlabsDLLMixin
**kwargs)

if '(Simulated)' not in self.model():
self.snapshot(True)

self.connect_message()

def _import_device_dll(self):
"""Import the device-specific DLLs and classes from the .NET API."""
self._add_dll('Thorlabs.MotionControl.GenericMotorCLI.dll')
self._add_dll('Thorlabs.MotionControl.KCube.DCServoCLI.dll')
self._import_dll_class('Thorlabs.MotionControl.KCube.DCServoCLI', 'KCubeDCServo')

def _get_api_interface_from_dll(self, serial_number: str):
"""Retrieve the API interface for the Thorlabs device using its serial number."""
return self._dll.KCubeDCServo.CreateKCubeDCServo(serial_number)

def _post_connection(self):
"""
Will run after after establishing a connection, updating 'get_idn'
and adding parameters 'model', 'serial_number' and 'firmware_version'.
"""
knownmodels = [
'KDC101'#,
#'KDC101 (Simulated)'
]
if self.model() not in knownmodels:
raise ValueError(f"'{self.model()}' is an unknown model.")

def _post_enable(self):
"""
This method can be overwritten by a subclass.
Will run after polling has started and the device/channel is enabled.
"""
# Load any configuration settings needed by the device/channel
serial = self._serial_number
mode = self._startup_mode
self._configuration = (
self._api_interface.LoadMotorConfiguration(serial, mode))

self._configuration.DeviceSettingsName = self._actuator_name
self._configuration.UpdateCurrentConfiguration()

self._api_interface.SetSettings(self._api_interface.MotorDeviceSettings, True, False)
sleep(0.5)
Loading