Skip to content

Commit 4495e22

Browse files
committed
Added KJL300 pressure gauge
1 parent 830d1df commit 4495e22

File tree

9 files changed

+217
-1
lines changed

9 files changed

+217
-1
lines changed
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
pylablib.devices.KJL package
2+
============================
3+
4+
Submodules
5+
----------
6+
7+
pylablib.devices.KJL.base module
8+
--------------------------------
9+
10+
.. automodule:: pylablib.devices.KJL.base
11+
:members:
12+
:inherited-members:
13+
:undoc-members:
14+
:show-inheritance:
15+
16+
17+
Module contents
18+
---------------
19+
20+
.. automodule:: pylablib.devices.KJL
21+
:members:
22+
:inherited-members:
23+
:undoc-members:
24+
:show-inheritance:

docs/.apidoc/pylablib.devices.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ Subpackages
1717
pylablib.devices.HighFinesse
1818
pylablib.devices.IMAQ
1919
pylablib.devices.IMAQdx
20+
pylablib.devices.KJL
2021
pylablib.devices.Lakeshore
2122
pylablib.devices.LaserQuantum
2223
pylablib.devices.Leybold

docs/devices/KJL.rst

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
.. _sensors_kjl:
2+
3+
.. note::
4+
Basic sensors communication concepts are described on the corresponding :ref:`page <basic_sensors_basics>`
5+
6+
Kurt J. Lesker pressure gauges
7+
==============================
8+
9+
KJL manufactures a range of pressure gauges and controllers with several different standards and communication protocols. The code has been tested with KJL300 pressure gauge using its built-in RS232 connection.
10+
11+
The main device classes are :class:`pylablib.devices.KJL.KJL300<.KJL.base.KJL300>`.
12+
13+
14+
Software requirements
15+
-----------------------
16+
17+
The devices provide a bare RS232 interface, so any appropriate USB-to-RS232 adapter should work.
18+
19+
20+
Connection
21+
-----------------------
22+
23+
Since the devices are identified as COM ports, they use the standard :ref:`connection method <devices_connection>`, and all you need to know is their COM-port address (e.g., ``COM5``)::
24+
25+
>> from pylablib.devices import KJL
26+
>> gauge = KJL.KJL300("COM5")
27+
>> gauge.close()
28+
29+
30+
Operation
31+
-----------------------
32+
33+
KJL300
34+
~~~~~~~~~~~~~~~~~~~~~~~
35+
36+
The operation of this gauge is fairly straightforward, but there is a couple of points to keep in mind:
37+
38+
- Even standard RS232 operation requires specifying the device RS485 address. IT can be specified using ``addr`` parameter on creation. By default, the class assumes the factory default of 1, but if it is ever changed on the device, it needs to be specified correctly.
39+
- By default, the pressure is always returned and set in Pa regardless of the display units.

docs/devices/basic_sensors_list.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@
33
- :ref:`Lakeshore <sensors_lakeshore>`: temperature sensors. Tested with Lakeshore 218.
44
- :ref:`Pfeiffer <sensors_pfeiffer>`: pressure gauges. Tested with TPG261 and DPG202 controllers.
55
- :ref:`Leybold <sensors_leybold>`: pressure gauges. Tested with ITR90 gauge.
6+
- :ref:`Kurt J. Lesker <sensors_kjl>`: pressure gauges. Tested with KJL300 gauge.
67
- :ref:`Thorlabs quadrature detector controller <stages_thorlabs_kinesis_quad>`. Tested with TPA101.

docs/devices/basic_sensors_root.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,5 @@ Currently supported sensors:
1818
Ophir
1919
Lakeshore
2020
Pfeiffer
21-
Leybold
21+
Leybold
22+
KJL

pylablib/devices/KJL/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from .base import KJL300, KJLError

pylablib/devices/KJL/base.py

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
from ...core.devio import comm_backend
2+
3+
import collections
4+
import re
5+
import time
6+
7+
8+
9+
class KJLError(comm_backend.DeviceError):
10+
"""Generic KJL device error"""
11+
class KJLBackendError(KJLError,comm_backend.DeviceBackendError):
12+
"""Generic KJL backend communication error"""
13+
14+
15+
16+
TKJL300DeviceInfo=collections.namedtuple("TKJL300DeviceInfo",["swver"])
17+
class KJL300(comm_backend.ICommBackendWrapper):
18+
"""
19+
KJL300 series pressure gauge.
20+
21+
Args:
22+
conn: serial connection parameters (usually port or a tuple containing port and baudrate)
23+
addr: RS485 address (reqired both for RS-485 and for RS-232 communication; factory default is 1)
24+
"""
25+
Error=KJLError
26+
def __init__(self, conn, addr=1):
27+
instr=comm_backend.new_backend(conn,"serial",term_read="\r",term_write="\r",defaults={"serial":("COM1",19200)},datatype="str",reraise_error=KJLBackendError)
28+
comm_backend.ICommBackendWrapper.__init__(self,instr)
29+
self.addr=addr
30+
self._add_info_variable("device_info",self.get_device_info)
31+
self._add_status_variable("pressure",self.get_pressure,priority=5)
32+
self._add_settings_variable("relay_setpoints",self.get_relay_setpoints,self.set_relay_setpoints,mux=((1,2),))
33+
try:
34+
self.query("VER")
35+
except self.instr.Error:
36+
self.close()
37+
raise
38+
39+
def _make_msg(self, msg):
40+
return "#{:02X}{}".format(self.addr,msg)
41+
_reply_re=re.compile(r"^(\*|\?)(\d{2}) (.*)$")
42+
def _parse_reply(self, msg):
43+
m=self._reply_re.match(msg)
44+
if m is None:
45+
raise self.Error("can not parse the reply: {}".format(msg))
46+
if int(m[2])!=self.addr:
47+
raise self.Error("reply address {} does not agree with the set address {}".format(int(m[1]),self.addr))
48+
if m[1]=="?":
49+
raise self.Error("request raised an error: {}".format(m[3]))
50+
return m[3]
51+
def comm(self, msg):
52+
"""Send a command to the device"""
53+
fmsg=self._make_msg(msg)
54+
freply=self.instr.ask(fmsg)
55+
reply=self._parse_reply(freply)
56+
if reply!="PROGM OK":
57+
raise self.Error("unexpected command reply: '{}' (expect '{}')".format(reply,"PROGM OK"))
58+
def query(self, msg):
59+
fmsg=self._make_msg(msg)
60+
freply=self.instr.ask(fmsg)
61+
return self._parse_reply(freply)
62+
63+
def get_device_info(self):
64+
"""Get device info (a tuple ``(swver)``)"""
65+
return TKJL300DeviceInfo(self.query("VER"))
66+
67+
def reset(self, confirm_addr=False):
68+
"""
69+
Reset the controller.
70+
71+
If ``confirm_addr==True``, set current RS485 address again (required for resetting after some commands).
72+
"""
73+
if confirm_addr:
74+
self.comm("SA{:02X}".format(self.addr))
75+
fmsg=self._make_msg("RST")
76+
self.instr.write(fmsg)
77+
time.sleep(50E-3)
78+
79+
def _toPa(self, v):
80+
return float(v)*133.322 # return and set values are always in Torr
81+
def _fromPa(self, v):
82+
return "{:0.2E}".format(v/133.322) # return and set values are always in Torr
83+
def get_pressure(self):
84+
"""Get current pressure in Pa"""
85+
return self._toPa(self.query("RD"))
86+
87+
def get_relay_setpoints(self, relay=1):
88+
"""
89+
Get relay setpoints (in Pa).
90+
91+
`relay` is the relay index (either 1 or 2).
92+
Return tuple ``(on, off)`` for on-below and off-above pressures (``on`` is always smaller than ``off``)
93+
"""
94+
q="RL" if relay==1 else "RH"
95+
return self._toPa(self.query("{}+".format(q))),self._toPa(self.query("{}-".format(q)))
96+
def set_relay_setpoints(self, relay=1, on=None, off=None, reset=True):
97+
"""
98+
Set relay setpoints (in Pa).
99+
100+
`relay` is the relay index (either 1 or 2). `on` and `off` are on-below and off-above pressures (``on`` is always smaller than ``off``).
101+
If ``reset==True``, reset the device after changing the setpoints (required to take effect).
102+
``None`` values are left unchanged.
103+
"""
104+
q="SL" if relay==1 else "SH"
105+
if on is not None:
106+
self.comm("{}+{}".format(q,self._fromPa(on)))
107+
if off is not None:
108+
self.comm("{}-{}".format(q,self._fromPa(off)))
109+
if reset:
110+
self.reset(confirm_addr=True)
111+
return self.get_relay_setpoints()
112+
def set_zero(self, pressure=0):
113+
"""Set vacuum calibration point (in Pa)"""
114+
self.comm("TZ{}".format(self._fromPa(pressure)))
115+
def set_span(self, pressure=1E5):
116+
"""Set atmosphere calibration point (in Pa)"""
117+
self.comm("TS{}".format(self._fromPa(pressure)))
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from .base import KJL300Thread
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
from ... import device_thread
2+
3+
4+
class KJL300Thread(device_thread.DeviceThread):
5+
"""
6+
KJL300 pressure gauge device thread.
7+
8+
Device args:
9+
- ``conn``: device connection (usually, COM-port address)
10+
- ``addr``: RS485 address (reqired both for RS-485 and for RS-232 communication; factory default is 1)
11+
12+
Variables:
13+
- ``pressure``: last measured pressure
14+
"""
15+
def connect_device(self):
16+
with self.using_devclass("KJL.KJL300",host=self.remote) as cls:
17+
self.device=cls(conn=self.conn,addr=self.addr)
18+
def setup_task(self, conn, addr=1, remote=None):
19+
self.device_reconnect_tries=5
20+
self.conn=conn
21+
self.addr=addr
22+
self.remote=remote
23+
self.add_job("update_measurements",self.update_measurements,.5)
24+
self.add_job("update_parameters",self.update_parameters,5)
25+
def update_measurements(self):
26+
"""Update current measurements"""
27+
if self.open():
28+
self.v["pressure"]=self.device.get_pressure()
29+
else:
30+
self.v["pressure"]=0
31+
self.sleep(1.)

0 commit comments

Comments
 (0)