Skip to content

Commit 2b08431

Browse files
zaberstage: Remote value check, and docstrings for labscript_devices classes.
1 parent d07ae49 commit 2b08431

File tree

4 files changed

+91
-27
lines changed

4 files changed

+91
-27
lines changed

ZaberStageController/blacs_tabs.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,9 @@ def initialise_GUI(self):
3838
'step': self.base_step,
3939
'decimals': self.base_decimals,
4040
}
41-
# Sort by stage number:
41+
# Sort by device number:
4242
ao_prop = {c: ao_prop[c] for c in sorted(ao_prop, key=get_device_number)}
43+
self.child_connections = list(ao_prop.keys())
4344
# Create the output objects
4445
self.create_analog_outputs(ao_prop)
4546
# Create widgets for output objects
@@ -48,14 +49,18 @@ def initialise_GUI(self):
4849
self.auto_place_widgets(("Zaber Stages", ao_widgets))
4950

5051
# Set the capabilities of this device
51-
self.supports_remote_value_check(False) # TODO: Implement
52-
self.supports_smart_programming(False) #TODO: Implement
52+
self.supports_remote_value_check(True)
53+
self.supports_smart_programming(False) #TODO: Implement?
5354

5455
def initialise_workers(self):
5556
# Create and set the primary worker
5657
self.create_worker(
5758
"main_worker",
5859
"labscript_devices.ZaberStageController.blacs_workers.ZaberWorker",
59-
{'com_port': self.com_port, 'mock': self.mock},
60+
{
61+
'com_port': self.com_port,
62+
'mock': self.mock,
63+
'child_connections': self.child_connections,
64+
},
6065
)
6166
self.primary_worker = "main_worker"

ZaberStageController/blacs_workers.py

Lines changed: 32 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -18,19 +18,27 @@
1818

1919
from .utils import get_device_number
2020

21+
22+
zaber = None
23+
24+
TIMEOUT = 60
25+
26+
2127
class MockZaberInterface(object):
22-
def __init__(self, port):
23-
pass
28+
def __init__(self, com_port):
29+
from collections import defaultdict
30+
self.positions = defaultdict(int)
31+
32+
def move(self, device_number, position):
33+
print(f"Mock move device {device_number} to position {position}")
34+
self.positions[device_number] = position
2435

25-
def move(self, stage_number, position):
26-
print(f"Mock move stage {stage_number} to position {position}")
36+
def get_position(self, device_number):
37+
return self.positions[device_number]
2738

2839
def close(self):
2940
print(f"mock close")
3041

31-
zaber = None
32-
33-
TIMEOUT = 60
3442

3543
class ZaberInterface(object):
3644
def __init__(self, com_port):
@@ -44,33 +52,42 @@ def __init__(self, com_port):
4452

4553
self.port = zaber.BinarySerial(com_port)
4654

47-
def move(self, stage_number, position):
48-
device = zaber.BinaryDevice(self.port, stage_number)
55+
def move(self, device_number, position):
56+
device = zaber.BinaryDevice(self.port, device_number)
4957
device.move_abs(position)
5058
deadline = monotonic() + TIMEOUT
5159
while device.get_position() != position:
5260
if monotonic() > deadline:
5361
msg = "Device did not move to requested position within timeout"
5462
raise TimeoutError(msg)
5563

64+
def get_position(self, device_number):
65+
device = zaber.BinaryDevice(self.port, device_number)
66+
return device.get_position()
67+
5668
def close(self):
5769
self.port.close()
5870

71+
5972
class ZaberWorker(Worker):
6073
def init(self):
6174
if self.mock:
6275
self.controller = MockZaberInterface(self.com_port)
6376
else:
6477
self.controller = ZaberInterface(self.com_port)
6578

79+
def check_remote_values(self):
80+
remote_values = {}
81+
for connection in self.child_connections:
82+
device_number = get_device_number(connection)
83+
remote_values[connection] = self.controller.get_position(device_number)
84+
return remote_values
85+
6686
def program_manual(self, values):
6787
for connection, value in values.items():
68-
stage_number = get_device_number(connection)
69-
self.controller.move(stage_number, int(round(value)))
70-
#TODO: return actual position of the zaber stage. Are they readable? Check API
71-
return values
72-
73-
# TODO: home stage function?
88+
device_number = get_device_number(connection)
89+
self.controller.move(device_number, int(round(value)))
90+
return self.check_remote_values()
7491

7592
def transition_to_buffered(self, device_name, h5file, initial_values, fresh):
7693
with h5py.File(h5file) as hdf5_file:
@@ -80,7 +97,6 @@ def transition_to_buffered(self, device_name, h5file, initial_values, fresh):
8097
values = {name: data[0][name] for name in data.dtype.names}
8198
else:
8299
values = {}
83-
84100
return self.program_manual(values)
85101

86102
def transition_to_manual(self):

ZaberStageController/labscript_devices.py

Lines changed: 48 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,36 @@
1717

1818
# Base class for stages:
1919
class ZaberStage(StaticAnalogQuantity):
20-
limits = (-np.inf, np.inf)
20+
limits = (0, np.inf)
2121
description = "Zaber Stage"
2222
@set_passed_properties(
2323
property_names={"connection_table_properties": ["limits"]}
2424
)
2525
def __init__(self, *args, limits=None, **kwargs):
26+
"""Static Analog output device for controlling the position of a Zaber stage.
27+
Can be added as a child device of `ZaberStageController`. Subclasses for
28+
specific models already have model-specific limits set for their values, but you
29+
may further restrict these by setting the keyword argument limits=
30+
31+
Args:
32+
*args:
33+
Arguments to be passed to the `__init__` method of the parent class
34+
(StaticAnalogQuantity).
35+
36+
limits (tuple), default `None`
37+
a two-tuple (min, max) for the minimum and maximum allowed positions, in
38+
steps, that the device may be instructed to move to via a labscript
39+
experiment or the BLACS front panel. If None, the limits set as a class
40+
attribute will be used, which are set to the maximal positions allowed
41+
by the device if using one of the model-specific subclasses defined in
42+
this module, or is (0, inf) otherwise.
43+
44+
**kwargs:
45+
Further keyword arguments to be passed to the `__init__` method of the
46+
parent class (StaticAnalogQuantity).
47+
48+
"""
49+
2650
if limits is None:
2751
limits = self.limits
2852
StaticAnalogQuantity.__init__(self, *args, limits=limits, **kwargs)
@@ -47,13 +71,33 @@ class ZaberStageTLS28M(ZaberStage):
4771

4872
class ZaberStageController(IntermediateDevice):
4973
allowed_children = [ZaberStage]
50-
generation = 0
5174

5275
@set_passed_properties(
5376
property_names={"connection_table_properties": ["com_port", "mock"]}
5477
)
55-
def __init__(self, name, com_port="", mock=False):
56-
IntermediateDevice.__init__(self, name, None)
78+
def __init__(self, name, com_port="COM1", mock=False, **kwargs):
79+
"""Device for controlling a number of Zaber stages connected to a serial port.
80+
Add stages as child devices, either by using one of them model-specific classes
81+
in this module, or the generic `ZaberStage` class.
82+
83+
Args:
84+
name (str)
85+
device name
86+
87+
com_port (str), default: `'COM1'`
88+
Serial port for communication, i.e. `'COM1' etc on Windows or
89+
`'/dev/USBtty0'` or similar on unix.
90+
91+
mock (bool, optional), default: False
92+
For testing purpses, simulate a device instead of communicating with
93+
actual hardware.
94+
95+
**kwargs: Further keyword arguments to be passed to the `__init__` method of
96+
the parent class (IntermediateDevice).
97+
98+
"""
99+
100+
IntermediateDevice.__init__(self, name, None, **kwargs)
57101
self.BLACS_connection = com_port
58102

59103
def add_device(self, device):

ZaberStageController/testing/test.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,14 @@
55
# labscript_init('test.h5', new=True, overwrite=True)
66

77
from labscript_devices.ZaberStageController.labscript_devices import (
8-
ZaberStageTLS28M,
8+
ZaberStage,
99
ZaberStageController,
1010
)
1111
from labscript import start, stop
1212

1313
DummyPseudoclock()
1414
ZaberStageController('controller', com_port='COM1', mock=MOCK)
15-
ZaberStageTLS28M('stage', controller, 'stage 1', limits=(0, 30000))
16-
# ZaberStageTLS28M('stage2', controller, 'stage 2')
15+
ZaberStage('stage', controller, 'device 1', limits=(0, 30000))
1716

1817
start()
1918

0 commit comments

Comments
 (0)