PySigmaKoki 2.1.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,29 @@
|
|
1
|
+
Metadata-Version: 2.1
|
2
|
+
Name: PySigmaKoki
|
3
|
+
Version: 2.1.3
|
4
|
+
Summary: Python Interface for Instruments by Sigma Koki
|
5
|
+
Author-email: Akira Okumura <oxon@mac.com>
|
6
|
+
License: BSD License
|
7
|
+
Project-URL: Repository, https://github.com/akira-okumura/PySigmaKoki.git
|
8
|
+
Project-URL: Issues, https://github.com/akira-okumura/PySigmaKoki/issues
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
10
|
+
Classifier: License :: OSI Approved :: BSD License
|
11
|
+
Classifier: Operating System :: OS Independent
|
12
|
+
Description-Content-Type: text/markdown
|
13
|
+
Requires-Dist: pyserial
|
14
|
+
|
15
|
+
# PySigmaKoki
|
16
|
+
Python module to control Sigma Koki stages
|
17
|
+
|
18
|
+
# Install
|
19
|
+
$ pip install -i https://pypi.anaconda.org/oxon/simple pysigmakoki
|
20
|
+
|
21
|
+
# Example
|
22
|
+
>>> import sigma_koki
|
23
|
+
>>> gsc02 = sigma_koki.GSC02()
|
24
|
+
>>> gsc02.open('/dev/tty.usbserial-FTT75V89A')
|
25
|
+
>>> gsc02.setSpeed(1, 50, 20000, 1000, 50, 20000, 1000)
|
26
|
+
>>> gsc02.returnToMechanicalOrigin('+', '+')
|
27
|
+
>>> gsc02.move(-50000, -50000)
|
28
|
+
>>> gsc02.getStatus()
|
29
|
+
'- 50000,- 50000,K,K,R'
|
@@ -0,0 +1,5 @@
|
|
1
|
+
sigma_koki.py,sha256=wKozv-LgckuduhMAgyxqHouSR4MnQl87qQDgpOxuJ2M,10733
|
2
|
+
PySigmaKoki-2.1.3.dist-info/METADATA,sha256=ueqhmN4z_qWsjD1yjYvowYgwsv4mXNJKYv4-QwV9Qvw,999
|
3
|
+
PySigmaKoki-2.1.3.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
4
|
+
PySigmaKoki-2.1.3.dist-info/top_level.txt,sha256=Zbq-FJdx-r0smE3UcnxNBcJ2wVwCX8pGfow0rejSOWk,11
|
5
|
+
PySigmaKoki-2.1.3.dist-info/RECORD,,
|
@@ -0,0 +1 @@
|
|
1
|
+
sigma_koki
|
sigma_koki.py
ADDED
@@ -0,0 +1,315 @@
|
|
1
|
+
"""
|
2
|
+
This is an interface module for instruments produced by Sigma Koki
|
3
|
+
"""
|
4
|
+
|
5
|
+
try:
|
6
|
+
# It is not needed to import ValueError in newer Python versions
|
7
|
+
from exceptions import ValueError
|
8
|
+
except:
|
9
|
+
pass
|
10
|
+
import serial
|
11
|
+
import sys
|
12
|
+
|
13
|
+
class BaseStageController(object):
|
14
|
+
"""
|
15
|
+
Stage controller class commonly used for Sigma Koki GSC02 and SHOT702
|
16
|
+
"""
|
17
|
+
def __init__(self, baudrate, product):
|
18
|
+
self.__baudRate = baudrate
|
19
|
+
self.__parityBit = 'N' # None
|
20
|
+
self.__dataBit = 8
|
21
|
+
self.__stopBit = 1
|
22
|
+
self.__rtscts = True
|
23
|
+
self.__product = product
|
24
|
+
self.__acknowledge = True
|
25
|
+
|
26
|
+
def setBaudRate(self, rate):
|
27
|
+
rates = {'GSC-02': (2400, 4800, 9600, 19200),
|
28
|
+
'SHOT-702' : (38400,),
|
29
|
+
'SHOT-702H' : (38400,)}
|
30
|
+
if rate in rates[self.__product]:
|
31
|
+
self.__baudRate = rate
|
32
|
+
else:
|
33
|
+
raise ValueError('Attempting to set an invalid buard rate of %d to %s. The rate must be chosen from %s.' % (rate, self.__product, rates[self.__product]))
|
34
|
+
|
35
|
+
def disableAcknowledge(self):
|
36
|
+
self.__acknowledge = False
|
37
|
+
|
38
|
+
def write(self, command, acknowledge=True):
|
39
|
+
# 'str' class needs be converted into 'bytes'
|
40
|
+
# e.g., 'command' -> b'command'
|
41
|
+
self.serial.write((command + '\r\n').encode())
|
42
|
+
|
43
|
+
if not self.__acknowledge or not acknowledge:
|
44
|
+
return
|
45
|
+
|
46
|
+
ack = self.readline()
|
47
|
+
if ack == 'OK':
|
48
|
+
return
|
49
|
+
else:
|
50
|
+
raise RuntimeError('%s returned bad acknowledge "%s"' % (self.__product, ack))
|
51
|
+
|
52
|
+
def query(self, command):
|
53
|
+
self.write(command, False)
|
54
|
+
return self.readline()
|
55
|
+
|
56
|
+
def readline(self):
|
57
|
+
# convert 'bytes' to 'str'
|
58
|
+
result = str(self.serial.readline())
|
59
|
+
if result[:2] == "b'" and result[-1:] == "'":
|
60
|
+
result = result[2:-1] # drop byte code prefix and suffix
|
61
|
+
if result[-4:] == '\\r\\n':
|
62
|
+
result = result[:-4] # drop delimeter
|
63
|
+
|
64
|
+
return result
|
65
|
+
|
66
|
+
def open(self, port, readTimeOut = 1, writeTimeOut = 1):
|
67
|
+
self.serial = serial.Serial(port = port,
|
68
|
+
baudrate = self.__baudRate,
|
69
|
+
bytesize = self.__dataBit,
|
70
|
+
parity = self.__parityBit,
|
71
|
+
stopbits = self.__stopBit,
|
72
|
+
timeout = readTimeOut,
|
73
|
+
writeTimeout = writeTimeOut,
|
74
|
+
rtscts = self.__rtscts)
|
75
|
+
|
76
|
+
def close(self):
|
77
|
+
self.serial.close()
|
78
|
+
|
79
|
+
def returnToMechanicalOrigin(self, stage1, stage2):
|
80
|
+
"""
|
81
|
+
Moves the stages to the +/- end points and reset the coordinate values
|
82
|
+
to zero.
|
83
|
+
"""
|
84
|
+
if self.__product == 'GSC-02':
|
85
|
+
if stage1 == '+' and stage2 == '+':
|
86
|
+
self.write('H:W++')
|
87
|
+
elif stage1 == '+' and stage2 == '-':
|
88
|
+
self.write('H:W+-')
|
89
|
+
elif stage1 == '-' and stage2 == '+':
|
90
|
+
self.write('H:W-+')
|
91
|
+
elif stage1 == '-' and stage2 == '-':
|
92
|
+
self.write('H:W--')
|
93
|
+
elif stage1 == '+':
|
94
|
+
self.write('H:1+')
|
95
|
+
elif stage1 == '-':
|
96
|
+
self.write('H:1-')
|
97
|
+
elif stage2 == '+':
|
98
|
+
self.write('H:2+')
|
99
|
+
elif stage2 == '-':
|
100
|
+
self.write('H:2-')
|
101
|
+
else:
|
102
|
+
return
|
103
|
+
elif self.__product == 'SHOT-702':
|
104
|
+
if stage1 == True and stage2 == True:
|
105
|
+
self.write('H:W')
|
106
|
+
elif stage1 == True:
|
107
|
+
self.write('H:1')
|
108
|
+
elif stage2 == True:
|
109
|
+
self.write('H:2')
|
110
|
+
else:
|
111
|
+
return
|
112
|
+
|
113
|
+
def move(self, stage1, stage2):
|
114
|
+
"""
|
115
|
+
Moves the stages with the specified values. Since GSC-02 is a half-step
|
116
|
+
stepping driver, 1 pulse corresponds to "half-step movement" in the
|
117
|
+
stage catalogues.
|
118
|
+
"""
|
119
|
+
if self.__product == 'GSC-02':
|
120
|
+
limit = 16777214
|
121
|
+
elif self.__product == 'SHOT-702':
|
122
|
+
limit = 268435455
|
123
|
+
|
124
|
+
if not (-limit <= stage1 <= limit):
|
125
|
+
raise ValueError('stage1 must be between -%d and %d.' % (limit, limit))
|
126
|
+
|
127
|
+
if not (-limit <= stage2 <= limit):
|
128
|
+
raise ValueError('stage2 must be between -%d and %d.' % (limit, limit))
|
129
|
+
|
130
|
+
command = 'M:W'
|
131
|
+
if stage1 >= 0:
|
132
|
+
command += '+P%d' % stage1
|
133
|
+
else:
|
134
|
+
command += '-P%d' % -stage1
|
135
|
+
|
136
|
+
if stage2 >= 0:
|
137
|
+
command += '+P%d' % stage2
|
138
|
+
else:
|
139
|
+
command += '-P%d' % -stage2
|
140
|
+
|
141
|
+
self.write(command)
|
142
|
+
self.go()
|
143
|
+
|
144
|
+
def jog(self, stage1, stage2):
|
145
|
+
"""
|
146
|
+
Moves the stages continuously at the minimum speed.
|
147
|
+
stage1: '+' positive direction, '-' negative direction
|
148
|
+
stage2: '+' positive direction, '-' negative direction
|
149
|
+
If other values are given, stages will not move.
|
150
|
+
"""
|
151
|
+
if stage1 == '+' and stage2 == '+':
|
152
|
+
self.write('J:W++')
|
153
|
+
elif stage1 == '+' and stage2 == '-':
|
154
|
+
self.write('J:W+-')
|
155
|
+
elif stage1 == '-' and stage2 == '+':
|
156
|
+
self.write('J:W-+')
|
157
|
+
elif stage1 == '-' and stage2 == '-':
|
158
|
+
self.write('J:W--')
|
159
|
+
elif stage1 == '+':
|
160
|
+
self.write('J:1+')
|
161
|
+
elif stage1 == '-':
|
162
|
+
self.write('J:1-')
|
163
|
+
elif stage2 == '+':
|
164
|
+
self.write('J:2+')
|
165
|
+
elif stage2 == '-':
|
166
|
+
self.write('J:2-')
|
167
|
+
else:
|
168
|
+
return
|
169
|
+
|
170
|
+
self.go()
|
171
|
+
|
172
|
+
def go(self):
|
173
|
+
"""
|
174
|
+
Moves the stages. To be used internally.
|
175
|
+
"""
|
176
|
+
self.write('G')
|
177
|
+
|
178
|
+
def decelerate(self, stage1, stage2):
|
179
|
+
"""
|
180
|
+
Decelerates and stop the stages.
|
181
|
+
"""
|
182
|
+
if stage1 and stage2:
|
183
|
+
self.write('L:W')
|
184
|
+
elif stage1:
|
185
|
+
self.write('L:1')
|
186
|
+
elif stage2:
|
187
|
+
self.write('L:2')
|
188
|
+
|
189
|
+
def stop(self):
|
190
|
+
"""
|
191
|
+
Stops the stages immediately.
|
192
|
+
"""
|
193
|
+
self.write('L:E')
|
194
|
+
|
195
|
+
def initializeOrigin(self, stage1, stage2):
|
196
|
+
"""
|
197
|
+
Sets the origin to the current position.
|
198
|
+
stage1: If true, set the origin of the stage 1 to the current position
|
199
|
+
stage2: If true, set the origin of the stage 1 to the current position
|
200
|
+
"""
|
201
|
+
if stage1:
|
202
|
+
self.write('R:1')
|
203
|
+
|
204
|
+
if stage2:
|
205
|
+
self.write('R:2')
|
206
|
+
|
207
|
+
def enableMotorExcitation(self, stage1 = True, stage2 = False):
|
208
|
+
"""
|
209
|
+
Enables motor excitation
|
210
|
+
"""
|
211
|
+
if stage1 in (True, False):
|
212
|
+
self.write('C:1%d' % stage1)
|
213
|
+
|
214
|
+
if stage2 in (True, False):
|
215
|
+
self.write('C:2%d' % stage2)
|
216
|
+
|
217
|
+
def getStatus(self):
|
218
|
+
"""
|
219
|
+
Returns the status of the controller
|
220
|
+
"""
|
221
|
+
return self.query('Q:')
|
222
|
+
|
223
|
+
def getACK3(self):
|
224
|
+
"""
|
225
|
+
Returns the status of ACK3
|
226
|
+
"""
|
227
|
+
return self.query('!:')
|
228
|
+
|
229
|
+
def getVersion(self):
|
230
|
+
"""
|
231
|
+
Returns the ROM version
|
232
|
+
"""
|
233
|
+
return self.query('?:V')
|
234
|
+
|
235
|
+
class GSC02(BaseStageController):
|
236
|
+
"""
|
237
|
+
Stage controller GSC-02
|
238
|
+
"""
|
239
|
+
def __init__(self):
|
240
|
+
# 9600 bps the initial factory setting
|
241
|
+
BaseStageController.__init__(self, 9600, 'GSC-02')
|
242
|
+
self.disableAcknowledge()
|
243
|
+
|
244
|
+
def setSpeed(self, highspeed, minSpeed1, maxSpeed1, accelerationTime1,
|
245
|
+
minSpeed2, maxSpeed2, accelerationTime2):
|
246
|
+
"""
|
247
|
+
Sets the movement speeds of the stages
|
248
|
+
highspeed: If true, speed range is 50-20000, else 1-200
|
249
|
+
minSpeed1/2: Minimum speed (PPS)
|
250
|
+
maxSpeed1/2: Maximum speed (PPS)
|
251
|
+
accelerationTime1/2: Acceleration time to be taken from min to max (ms)
|
252
|
+
|
253
|
+
| _________ ... maximum speed (PPS)
|
254
|
+
| / \
|
255
|
+
| / \
|
256
|
+
| / \ ... minimum speed (PPS)
|
257
|
+
| | |
|
258
|
+
| | |
|
259
|
+
|__|______________|________
|
260
|
+
<-> acceleration time (ms)
|
261
|
+
<-> deceleration time (ms)
|
262
|
+
"""
|
263
|
+
if not highspeed:
|
264
|
+
if not (1 <= minSpeed1 <= maxSpeed1 <= 200):
|
265
|
+
raise ValueError('Must be 1 <= minSpeed1 <= maxSpeed1 <= 200 in low speed range.')
|
266
|
+
if not (1 <= minSpeed2 <= maxSpeed2 <= 200):
|
267
|
+
raise ValueError('Must be 1 <= minSpeed2 <= maxSpeed2 <= 200 in low speed range.')
|
268
|
+
else:
|
269
|
+
if not (50 <= minSpeed1 <= maxSpeed1 <= 20000):
|
270
|
+
raise ValueError('Must be 50 <= minSpeed1 <= maxSpeed1 <= 20000 in high speed range.')
|
271
|
+
if not (50 <= minSpeed2 <= maxSpeed2 <= 20000):
|
272
|
+
raise ValueError('Must be 50 <= minSpeed2 <= maxSpeed2 <= 20000 in high speed range.')
|
273
|
+
|
274
|
+
if not (0 <= accelerationTime1 <= 1000):
|
275
|
+
raise ValueError('Must be 0 <= accelerationTime1 <= 1000.')
|
276
|
+
|
277
|
+
if not (0 <= accelerationTime2 <= 1000):
|
278
|
+
raise ValueError('Must be 0 <= accelerationTime2 <= 1000.')
|
279
|
+
|
280
|
+
if highspeed:
|
281
|
+
self.write('D:2S%dF%dR%dS%dF%dR%d' % (minSpeed1, maxSpeed1, accelerationTime1, minSpeed2, maxSpeed2, accelerationTime2))
|
282
|
+
else:
|
283
|
+
self.write('D:1S%dF%dR%dS%dF%dR%d' % (minSpeed1, maxSpeed1, accelerationTime1, minSpeed2, maxSpeed2, accelerationTime2))
|
284
|
+
|
285
|
+
class SHOT702(BaseStageController):
|
286
|
+
"""
|
287
|
+
Stage controller SHOT-702
|
288
|
+
"""
|
289
|
+
def __init__(self):
|
290
|
+
# 9600 bps the initial factory setting
|
291
|
+
BaseStageController.__init__(self, 38400, 'SHOT-702')
|
292
|
+
|
293
|
+
def setSpeed(self, minSpeed1, maxSpeed1, accelerationTime1, minSpeed2, maxSpeed2, accelerationTime2):
|
294
|
+
"""
|
295
|
+
Sets the movement speeds of the stages
|
296
|
+
minSpeed1/2: Minimum speed (PPS)
|
297
|
+
maxSpeed1/2: Maximum speed (PPS)
|
298
|
+
accelerationTime1/2: Acceleration time to be taken from min to max (ms)
|
299
|
+
"""
|
300
|
+
if not (1 <= minSpeed1 <= maxSpeed1 <= 500000):
|
301
|
+
raise ValueError('Must be 1 <= minSpeed1 <= maxSpeed1 <= 500000.')
|
302
|
+
|
303
|
+
if not (1 <= minSpeed2 <= maxSpeed2 <= 500000):
|
304
|
+
raise ValueError('Must be 1 <= minSpeed2 <= maxSpeed2 <= 500000.')
|
305
|
+
|
306
|
+
if not (0 <= accelerationTime1 <= 1000):
|
307
|
+
raise ValueError('Must be 0 <= accelerationTime <= 1000.')
|
308
|
+
|
309
|
+
if not (0 <= accelerationTime2 <= 1000):
|
310
|
+
raise ValueError('Must be 0 <= accelerationTime <= 1000.')
|
311
|
+
|
312
|
+
self.write('D:WS%dF%dR%dS%dF%dR%d' % (minSpeed1, maxSpeed1, accelerationTime1, minSpeed2, maxSpeed2, accelerationTime2))
|
313
|
+
|
314
|
+
# Some query commands, ?:P, ?:S, ?:D, and ?:B, are not implemented yet
|
315
|
+
|