fixes for uniax device

This commit is contained in:
zolliker 2021-06-11 16:45:45 +02:00
parent 6c4bb78f97
commit b30bd308a9
11 changed files with 456 additions and 33 deletions

17
cfg/ls240.cfg Normal file
View File

@ -0,0 +1,17 @@
[NODE]
id = ls240.psi.ch
description = ls240 test
[INTERFACE]
uri = tcp://5000
[T]
description = temperature on uniax stick
class = secop_psi.ls240.Ls240
iodev = T_iodev
[T_iodev]
class = secop.bytesio.BytesIO
description = IO device for LS240
uri = serial:///dev/ttyUSB0?baudrate=9600+parity=EVEN
timeout = 0.2

View File

@ -8,25 +8,39 @@ uri = tcp://5000
[drv_iodev]
description =
class = secop.bytesio.BytesIO
uri = serial:///dev/ttyUSB0?baudrate=57600
# uri = serial:///dev/ttyUSB0?baudrate=9600
# uri = serial:///dev/ttyUSB1?baudrate=57600
uri = tcp://192.168.127.254:3002
[drv]
description = trinamic motor test
class = secop_psi.trinamic.Motor
iodev = drv_iodev
standby_current=0.1
maxcurrent=1.4
acceleration=50
maxspeed=200
zero=-36
enc_tolerance=3.6
free_wheeling=0.001
pull_up=1
maxcurrent=0.2
acceleration=150.
movelimit=360
speed=40
encoder_tolerance=3.6
free_wheeling=0.1
power_down_delay=0.1
[force]
description = DPM driver to read out the transducer value, write and read the offset and scale factor
class = secop_psi.dpm.DPM3
uri = serial:///dev/ttyUSB1?baudrate=9600
#uri = serial:///dev/ttyUSB0?baudrate=9600
uri = tcp://192.168.127.254:3001
digits = 2
scale_factor = 0.0156
motor = drv
[res]
description = temperature on uniax stick
class = secop_psi.ls340res.ResChannel
uri = tcp://192.168.127.254:3003
channel = C
[T]
class = secop_psi.softcal.Sensor
rawsensor = res
calib = /home/l_samenv/frappy/secop_psi/calcurves/X132254.340
value.unit = K

View File

@ -37,4 +37,5 @@ from secop.poller import AUTO, DYNAMIC, REGULAR, SLOW
from secop.properties import Property
from secop.proxy import Proxy, SecNode, proxy_class
from secop.stringio import HasIodev, StringIO
from secop.bytesio import BytesIO
from secop.persistent import PersistentMixin, PersistentParam

View File

@ -251,7 +251,9 @@ class AsynSerial(AsynConn):
if not fullname.startswith(name):
raise ConfigError('illegal parity: %s' % parity)
options['parity'] = name[0]
if 'timeout' not in options:
if 'timeout' in options:
options['timeout'] = float(self.timeout)
else:
options['timeout'] = self.timeout
try:
self.connection = Serial(dev, **options)

View File

@ -92,7 +92,7 @@ class PersistentMixin(HasAccessibles):
try:
with open(self.persistentFile, 'r') as f:
self.persistentData = json.load(f)
except FileNotFoundError:
except Exception:
self.persistentData = {}
writeDict = {}
for pname in self.parameters:

View File

@ -0,0 +1,208 @@
Sensor Model: CX-1050-SD 2018-11-20
Serial Number: X132254
Data Format: 4 (Log Ohms/Kelvin)
SetPoint Limit: 330.0 (Kelvin)
Temperature coefficient: 1 (Negative)
Number of Breakpoints: 199
No. Units Temperature (K)
1 1.865581 330.0000
2 1.889780 310.0000
3 1.900613 301.5330
4 1.911510 293.2973
5 1.922466 285.2865
6 1.933476 277.4945
7 1.944536 269.9153
8 1.955638 262.5431
9 1.966779 255.3723
10 1.977950 248.3974
11 1.989148 241.6129
12 2.000369 235.0138
13 2.011610 228.5949
14 2.022870 222.3513
15 2.034145 216.2782
16 2.045433 210.3710
17 2.056730 204.6252
18 2.068035 199.0363
19 2.079343 193.6000
20 2.090652 188.3123
21 2.101960 183.1689
22 2.113263 178.1660
23 2.124559 173.2998
24 2.135845 168.5665
25 2.147117 163.9624
26 2.158374 159.4842
27 2.169612 155.1282
28 2.180830 150.8912
29 2.192023 146.7699
30 2.203192 142.7612
31 2.214333 138.8620
32 2.225444 135.0693
33 2.236525 131.3801
34 2.247573 127.7918
35 2.258586 124.3014
36 2.269564 120.9064
37 2.280509 117.6041
38 2.291423 114.3920
39 2.302308 111.2676
40 2.313167 108.2285
41 2.324003 105.2725
42 2.334817 102.3972
43 2.345609 99.60045
44 2.356380 96.88007
45 2.367129 94.23400
46 2.377857 91.66019
47 2.388562 89.15669
48 2.399245 86.72156
49 2.409907 84.35294
50 2.420547 82.04902
51 2.431166 79.80803
52 2.441762 77.62824
53 2.452338 75.50799
54 2.462894 73.44565
55 2.473431 71.43963
56 2.483949 69.48841
57 2.494449 67.59048
58 2.504932 65.74439
59 2.515397 63.94872
60 2.525846 62.20210
61 2.536278 60.50318
62 2.546695 58.85066
63 2.557096 57.24328
64 2.567482 55.67980
65 2.577854 54.15902
66 2.588212 52.67978
67 2.598555 51.24095
68 2.608882 49.84141
69 2.619195 48.48010
70 2.629492 47.15596
71 2.639773 45.86800
72 2.650037 44.61521
73 2.660285 43.39664
74 2.670517 42.21135
75 2.680731 41.05844
76 2.690928 39.93701
77 2.701107 38.84622
78 2.711268 37.78522
79 2.721411 36.75319
80 2.731536 35.74936
81 2.741644 34.77294
82 2.751735 33.82319
83 2.761808 32.89938
84 2.771865 32.00080
85 2.781907 31.12677
86 2.791933 30.27661
87 2.801945 29.44966
88 2.811944 28.64531
89 2.821930 27.86292
90 2.831903 27.10191
91 2.841865 26.36167
92 2.851817 25.64166
93 2.861758 24.94131
94 2.871690 24.26009
95 2.881614 23.59748
96 2.891532 22.95297
97 2.901446 22.32605
98 2.911361 21.71626
99 2.921277 21.12313
100 2.931198 20.54620
101 2.941127 19.98502
102 2.951066 19.43917
103 2.961018 18.90823
104 2.970985 18.39179
105 2.980970 17.88946
106 2.990974 17.40085
107 3.001002 16.92558
108 3.011054 16.46329
109 3.021133 16.01363
110 3.031243 15.57626
111 3.041384 15.15082
112 3.051561 14.73701
113 3.061776 14.33450
114 3.072032 13.94298
115 3.082331 13.56216
116 3.092677 13.19174
117 3.103073 12.83143
118 3.113522 12.48097
119 3.124027 12.14008
120 3.134592 11.80850
121 3.145221 11.48597
122 3.155918 11.17226
123 3.166687 10.86711
124 3.177532 10.57030
125 3.188458 10.28159
126 3.199469 10.00077
127 3.210570 9.727624
128 3.221764 9.461935
129 3.233053 9.203502
130 3.244440 8.952128
131 3.255927 8.707619
132 3.267518 8.469789
133 3.279216 8.238455
134 3.291024 8.013439
135 3.302945 7.794568
136 3.314984 7.581676
137 3.327143 7.374599
138 3.339428 7.173177
139 3.351843 6.977257
140 3.364390 6.786688
141 3.377076 6.601324
142 3.389904 6.421023
143 3.402879 6.245646
144 3.416005 6.075059
145 3.429288 5.909132
146 3.442733 5.747736
147 3.456347 5.590749
148 3.470134 5.438050
149 3.484101 5.289521
150 3.498250 5.145049
151 3.512586 5.004522
152 3.527113 4.867834
153 3.541835 4.734880
154 3.556757 4.605557
155 3.571882 4.479766
156 3.587215 4.357410
157 3.602759 4.238397
158 3.618520 4.122634
159 3.634504 4.010033
160 3.650715 3.900507
161 3.667161 3.793973
162 3.683849 3.690349
163 3.700786 3.589555
164 3.717980 3.491514
165 3.735437 3.396150
166 3.753166 3.303392
167 3.771176 3.213166
168 3.789476 3.125406
169 3.808071 3.040042
170 3.826971 2.957009
171 3.846182 2.876245
172 3.865712 2.797686
173 3.885567 2.721273
174 3.905755 2.646948
175 3.926284 2.574652
176 3.947160 2.504331
177 3.968390 2.435930
178 3.989980 2.369398
179 4.011939 2.304683
180 4.034269 2.241735
181 4.056978 2.180507
182 4.080072 2.120951
183 4.103563 2.063022
184 4.127465 2.006675
185 4.151790 1.951866
186 4.176551 1.898555
187 4.201764 1.846700
188 4.227442 1.796262
189 4.253600 1.747201
190 4.280254 1.699479
191 4.307419 1.653062
192 4.335111 1.607912
193 4.363347 1.563995
194 4.392142 1.521278
195 4.421513 1.479727
196 4.451476 1.439312
197 4.482048 1.400000
198 4.664046 1.200000
199 4.907708 1.000000

View File

@ -16,11 +16,13 @@
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# Module authors:
# ...
# M. Zolliker <markus.zolliker@psi.ch>
#
# *****************************************************************************
"""transducer DPM3 read out"""
from secop.core import Readable, Parameter, FloatRange, BoolType, StringIO, HasIodev, IntRange, Done
from secop.core import Drivable, Parameter, FloatRange, BoolType, StringIO,\
HasIodev, IntRange, Done, Attached, Command
class DPM3IO(StringIO):
@ -43,7 +45,7 @@ def float2hex(value, digits):
return '%06X' % intvalue
class DPM3(HasIodev, Readable):
class DPM3(HasIodev, Drivable):
OFFSET = 0x8f
SCALE = 0x8c
@ -52,8 +54,11 @@ class DPM3(HasIodev, Readable):
iodevClass = DPM3IO
motor = Attached()
digits = Parameter('number of digits for value', IntRange(0, 5), initwrite=True, readonly=False)
value = Parameter(unit='N')
target = Parameter(unit='N')
step = Parameter('maximum motor step', FloatRange(unit='deg'), default=5, readonly=False)
offset = Parameter('', FloatRange(-1e5, 1e5), readonly=False, poll=True)
@ -62,6 +67,8 @@ class DPM3(HasIodev, Readable):
thus a maximl output of 1500. 10=150/f
"""
scale_factor = Parameter('', FloatRange(-1e5, 1e5, unit='input_units/N'), readonly=False, poll=True)
_target = None
fast_pollfactor = 0.01
def query(self, adr, value=None):
if value is not None:
@ -108,8 +115,36 @@ class DPM3(HasIodev, Readable):
return int(back_value,16) - 1
def read_value(self):
value = self._iodev.communicate('*1B1')
return float(value)
value = float(self._iodev.communicate('*1B1'))
if self._target is not None:
mot = self._motor
if self._direction * (self._target - value) > 0:
if not mot.isBusy():
step = self.step * self._direction
mot.write_target(mot.value + step)
else:
print(value)
self.stop()
self.status = self.Status.IDLE, 'target reached'
return value
def write_target(self, target):
self._target = target
if target - self.value > 0:
self._direction = 1
else:
self._direction = -1
print('direction', self._direction)
self.status = self.Status.BUSY, 'moving motor'
if self._motor.status[0] == self.Status.ERROR:
self._motor.reset()
return target
@Command()
def stop(self):
self._target = None
self._motor.stop()
self.status = self.Status.IDLE, 'stopped'
def read_offset(self):
reply = self.query(self.OFFSET)

102
secop_psi/ls240.py Normal file
View File

@ -0,0 +1,102 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# *****************************************************************************
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation; either version 2 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Software Foundation, Inc.,
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# Module authors:
# Markus Zolliker <markus.zolliker@psi.ch>
# *****************************************************************************
"""LakeShore 240 temperature monitor"""
import struct
from secop.core import FloatRange, HasIodev, Readable, Parameter, BytesIO
from secop.errors import CommunicationFailedError
SD1= 0x10
SD2= 0x68
FC = 0x49
ED = 0x16
STATUS_REQ = 0x49
def dehex(msg):
return bytes(int(b, 16) for b in msg.split())
def hexify(msg):
return ' '.join('%2.2X' % b for b in msg)
class Ls240(HasIodev, Readable):
value = Parameter('sensor reading', FloatRange(unit='Ohm'))
iodevClass = BytesIO
def request(self, replylen, data='', ext=None, dst_adr=3, src_adr=2):
data = dehex(data)
if ext is None:
ext = len(data) > 1
if ext:
dst_adr |= 0x80
src_adr |= 0x80
if len(data) > 1:
length = len(data) + 2
hdr = [SD2, length, length, SD2]
else:
hdr = [SD1]
mid = [dst_adr, src_adr] + list(data)
checksum = sum(mid) % 256
msg = bytes(hdr + mid + [checksum, ED])
for i in range(10):
try:
# print('>', hexify(msg))
reply = self._iodev.communicate(msg, replylen)
# print('<', hexify(reply))
except (TimeoutError, CommunicationFailedError):
continue
return reply
return None
def read_value(self):
# check connection
self.request(6, '49')
# get diag
# 3C: slave diag, (what means 3E?)
reply = self.request(17, '6D 3C 3E')
assert reply[13:15] == b'\x0f\x84' # LS240 ident
# set parameters
# 3D set param (what means 3E?)
# B0 FF FF: no watchdog, 00: min wait, 0F 84: ident, 01: group
assert b'\xe5' == self.request(1, '5D 3D 3E B0 FF FF 00 0F 84 01')
# set config
# 3E set config (what means 2nd 3E?)
# 93: input only, 4 == 3+1 bytes
assert b'\xe5' == self.request(1, '7D 3E 3E 93')
# get diag
# 3C: slave diag, (what means 3E?)
reply = self.request(17, '5D 3C 3E')
assert reply[13:15] == b'\x0f\x84' # LS240 ident
# get data
# do not know what 42 24 means
reply = self.request(13, '7D 42 24', ext=0)
print('DATA', reply)
value = struct.unpack('>f', reply[7:11])[0]
print('VALUE', value)
return value

45
secop_psi/ls340res.py Normal file
View File

@ -0,0 +1,45 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# *****************************************************************************
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation; either version 2 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Software Foundation, Inc.,
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# Module authors:
# Markus Zolliker <markus.zolliker@psi.ch>
# *****************************************************************************
"""very simple LakeShore Model 340 driver, resistivity only"""
import time
from secop.datatypes import StringType, FloatRange
from secop.modules import Parameter, Property, Readable
from secop.stringio import HasIodev, StringIO
class LscIO(StringIO):
identification = [('*IDN?', 'LSCI,MODEL340,.*')]
end_of_line = '\r'
wait_before = 0.05
class ResChannel(HasIodev, Readable):
"""temperature channel on Lakeshore 340"""
iodevClass = LscIO
value = Parameter(datatype=FloatRange(unit='Ohm'))
channel = Property('the channel A,B,C or D', StringType())
def read_value(self):
return self._iodev.communicate('SRDG?%s' % self.channel)

View File

@ -198,7 +198,7 @@ class Sensor(Readable):
def update_value(self, value):
if self.abs:
value = abs(value)
value = abs(float(value))
self.value = self._calib(value)
self._value_error = None

View File

@ -97,7 +97,7 @@ class Motor(PersistentMixin, HasIodev, Drivable):
FloatRange(0, 360., unit='$'),
212, ANGLE_SCALE, readonly=False, group='more')
speed = HwParam('max. speed', FloatRange(0, MAX_SPEED, unit='$/sec'),
4, SPEED_SCALE, readonly=False, group='more')
4, SPEED_SCALE, readonly=False, group='motorparam')
minspeed = HwParam('min. speed', FloatRange(0, MAX_SPEED, unit='$/sec'),
130, SPEED_SCALE, readonly=False, default=SPEED_SCALE, group='motorparam')
currentspeed = HwParam('current speed', FloatRange(-MAX_SPEED, MAX_SPEED, unit='$/sec'),
@ -221,7 +221,6 @@ class Motor(PersistentMixin, HasIodev, Drivable):
initialized = self.comm(GET_GLOB_PAR, 255, bank=2)
if initialized: # no power loss
self.saveParameters()
print('SAVED', self.persistentData)
else: # just powered up
# get persistent values
writeDict = self.loadParameters()
@ -403,18 +402,18 @@ class Motor(PersistentMixin, HasIodev, Drivable):
self.status = self.Status.IDLE, 'stopped'
self._started = 0
@Command()
def step(self):
self.comm(MOVE, 1, FULL_STEP / ANGLE_SCALE)
#@Command()
#def step(self):
# self.comm(MOVE, 1, FULL_STEP / ANGLE_SCALE)
@Command()
def back(self):
self.comm(MOVE, 1, - FULL_STEP / ANGLE_SCALE)
#@Command()
#def back(self):
# self.comm(MOVE, 1, - FULL_STEP / ANGLE_SCALE)
@Command(IntRange(), result=IntRange())
def get_axis_par(self, adr):
return self.comm(GET_AXIS_PAR, adr)
#@Command(IntRange(), result=IntRange())
#def get_axis_par(self, adr):
# return self.comm(GET_AXIS_PAR, adr)
@Command((IntRange(), FloatRange()), result=IntRange())
def set_axis_par(self, adr, value):
return self.comm(SET_AXIS_PAR, adr, value)
#@Command((IntRange(), FloatRange()), result=IntRange())
#def set_axis_par(self, adr, value):
# return self.comm(SET_AXIS_PAR, adr, value)