BioImager  3.9.1
A .NET microscopy imaging library. Supports various microscopes by using imported libraries & GUI automation. Supported libraries include PriorĀ® & ZeissĀ® & all devices supported by Micromanager 2.0 and python-microscope.
Loading...
Searching...
No Matches
thorlabs.py
1#!/usr/bin/env python3
2
3## Copyright (C) 2020 Mick Phillips <mick.phillips@gmail.com>
4##
5## This file is part of Microscope.
6##
7## Microscope is free software: you can redistribute it and/or modify
8## it under the terms of the GNU General Public License as published by
9## the Free Software Foundation, either version 3 of the License, or
10## (at your option) any later version.
11##
12## Microscope is distributed in the hope that it will be useful,
13## but WITHOUT ANY WARRANTY; without even the implied warranty of
14## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15## GNU General Public License for more details.
16##
17## You should have received a copy of the GNU General Public License
18## along with Microscope. If not, see <http://www.gnu.org/licenses/>.
19
20import io
21import string
22import threading
23import warnings
24
25import serial
26
27import microscope
28import microscope.abc
29
30
32 """Implements FilterServer wheel interface for Thorlabs FW102C.
33
34 Note that the FW102C also has manual controls on the device, so clients
35 should periodically query the current wheel position."""
36
37 def __init__(self, com, baud=115200, timeout=2.0, **kwargs):
38 """Create ThorlabsFilterWheel
39
40 :param com: COM port
41 :param baud: baud rate
42 :param timeout: serial timeout
43 """
44 self.eol = "\r"
45 rawSerial = serial.Serial(
46 port=com,
47 baudrate=baud,
48 timeout=timeout,
49 stopbits=serial.STOPBITS_ONE,
50 bytesize=serial.EIGHTBITS,
51 parity=serial.PARITY_NONE,
52 xonxoff=0,
53 )
54 # The Thorlabs controller serial implementation is strange.
55 # Generally, it uses \r as EOL, but error messages use \n.
56 # A readline after sending a 'pos?\r' command always times out,
57 # but returns a string terminated by a newline.
58 # We use TextIOWrapper with newline=None to perform EOL translation
59 # inbound, but must explicitly append \r to outgoing commands.
60 # The TextIOWrapper also deals with conversion between unicode
61 # and bytes.
62 self.connection = io.TextIOWrapper(
63 rawSerial,
64 newline=None,
65 line_buffering=True, # flush on write
66 write_through=True, # write out immediately
67 )
68 # A lock for the connection. We should probably be using
69 # SharedSerial (maybe change it to SharedIO, and have it
70 # accept any IOBase implementation).
71 self._lock = threading.RLock()
72 position_count = int(self._send_command("pcount?"))
73 super().__init__(positions=position_count, **kwargs)
74
75 def _do_shutdown(self) -> None:
76 pass
77
78 def _do_set_position(self, new_position: int) -> None:
79 # Thorlabs positions start at 1, hence the +1
80 self._send_command("pos=%d" % (new_position + 1))
81
82 def _do_get_position(self):
83 # Thorlabs positions start at 1, hence the -1
84 try:
85 return int(self._send_command("pos?")) - 1
86 except TypeError:
88 "Unable to get position of %s", self.__class__.__name__
89 )
90
91 def _readline(self):
92 """Custom _readline to overcome limitations of the serial implementation."""
93 result = []
94 with self._lock:
95 while not result or result[-1] not in ("\n", ""):
96 char = self.connection.read()
97 # Do not allow lines to be empty.
98 if result or (char not in string.whitespace):
99 result.append(char)
100 return "".join(result)
101
102 def _send_command(self, command):
103 """Send a command and return any result."""
104 with self._lock:
105 self.connection.write(command + self.eol)
106 response = "dummy"
107 while command not in response and ">" not in response:
108 # Read until we receive the command echo.
109 response = self._readline().strip()
110 if command.endswith("?"):
111 # Last response was the command. Next is result.
112 return self._readline().strip()
113 return None
114
115
117 """Deprecated, use ThorlabsFilterWheel.
118
119 This class is from when ThorlabsFilterWheel did not automatically
120 found its own number of positions and there was a separate class
121 for each thorlabs filterwheel model.
122 """
123
124 def __init__(self, *args, **kwargs):
125 warnings.warn(
126 "Use ThorlabsFilterWheel instead of ThorlabsFW102C",
127 DeprecationWarning,
128 stacklevel=2,
129 )
130 super().__init__(*args, **kwargs)
131 if self.n_positions != 6:
133 "Does not look like a FW102C, it has %d positions instead of 6"
134 )
135
136
138 """Deprecated, use ThorlabsFilterWheel.
139
140 This class is from when ThorlabsFilterWheel did not automatically
141 found its own number of positions and there was a separate class
142 for each thorlabs filterwheel model.
143 """
144
145 def __init__(self, *args, **kwargs):
146 warnings.warn(
147 "Use ThorlabsFilterWheel instead of ThorlabsFW212C",
148 DeprecationWarning,
149 stacklevel=2,
150 )
151 super().__init__(*args, **kwargs)
152 if self.n_positions != 12:
154 "Does not look like a FW212C, it has %d positions instead of 12"
155 )
int n_positions(self)
Definition: abc.py:1283
def __init__(self, com, baud=115200, timeout=2.0, **kwargs)
Definition: thorlabs.py:37