From 3938914420aaabb0e65cb8586dee8e41799f3875 Mon Sep 17 00:00:00 2001 From: AntonioT7 Date: Wed, 30 Nov 2022 14:44:40 +0100 Subject: [PATCH 01/21] new julabo fp50 --- basil/HL/julaboFP50.py | 95 +++++++++++++++++++ basil/HL/julabo_FP50.yaml | 13 +++ examples/lab_devices/julaboFP50.py | 17 ++++ examples/lab_devices/julaboFP50_pyserial.yaml | 20 ++++ 4 files changed, 145 insertions(+) create mode 100644 basil/HL/julaboFP50.py create mode 100644 basil/HL/julabo_FP50.yaml create mode 100644 examples/lab_devices/julaboFP50.py create mode 100644 examples/lab_devices/julaboFP50_pyserial.yaml diff --git a/basil/HL/julaboFP50.py b/basil/HL/julaboFP50.py new file mode 100644 index 00000000..682749a7 --- /dev/null +++ b/basil/HL/julaboFP50.py @@ -0,0 +1,95 @@ +# +# ------------------------------------------------------------ +# Copyright (c) All rights reserved +# SiLab, Institute of Physics, University of Bonn +# ------------------------------------------------------------ +# + +""" +This script is used to communicate with the chiller julabo fp50 +""" + +import logging +import time + +from basil.HL.RegisterHardwareLayer import HardwareLayer + + +logger = logging.getLogger(__name__) + + +class julaboFP50(HardwareLayer): + ''' Driver for the Julabo FP50 chiller. + A simple protocol via crossed null modem serial port is used with baud rate of 9600. + ''' + + def __init__(self, intf, conf): + super(julaboFP50, self).__init__(intf, conf) + self.pre_time = time.time() + + def init(self): + super(julaboFP50, self).init() + + def read(self): + ret = self._intf.read() + if len(ret) < 2 or ret[-2:] != "\r\n": + logger.warning("read() termination error") + return ret[:-2] + + def write(self, cmd): + if time.time() - self.pre_time < 1.0: + time.sleep(1.0) + self._intf.write(str(cmd)) + self.pre_time = time.time() + + def get_version(self): + ''' Read identifier + ''' + self.write("version") + ret = self.read() + return ret + + def start_chiller(self): + ''' Start chiller + ''' + self.write("out_mode_05 1") + + def stop_chiller(self): + ''' Stop chiller + ''' + self.write("out_mode_05 0") + + def get_status(self): + ''' Get status + ''' + self.write("status") + ret = self.read() + logger.debug("status:{:s}".format(ret)) + try: + tmp = ret.split(" ", 1) + status = int(tmp[0]) + status_str = tmp[1:] + except (ValueError, AttributeError): + logger.warning("get_status() wrong format: {}".format(repr(ret))) + status = -99 + status_str = ret + return status, status_str + + def get_set_temp(self): + '''get the set temperature + ''' + self.write("in_sp_00") + ret = self.read() + return float(ret) + + def set_temp(self, temp): + '''set the temperature to a value + ''' + self.write(f"out_sp_00={temp}") + + def get_temp(self): + '''get the current temperature in chiller + ''' + self.write("in_pv_00") + ret = self.read() + return float(ret) diff --git a/basil/HL/julabo_FP50.yaml b/basil/HL/julabo_FP50.yaml new file mode 100644 index 00000000..50a15e29 --- /dev/null +++ b/basil/HL/julabo_FP50.yaml @@ -0,0 +1,13 @@ +""" +Device description for using the julabo FP50 chiller +set_ function expect a parameter, get_ function return a parameter. +""" + +get_temp: in_sp_00 # get current set temperature +set_temp: out_sp_00 # set the temperature +get_curr_temp: in_pv_00 # get the current bath temperature +get_version: version # get the version of the device +get_status: status # see its status (manual start, remote control, ...) +set_power: out_hil_00 # Set the desired maximum cooling power (0% to 100%). Note: Enter the value with a preceding negative sign! This setting is meaningful only for FP cooling machines. +on: out_mode_05 1 # start (parameter 1) +off: out_mode_05 0 # stop (parameter 0) \ No newline at end of file diff --git a/examples/lab_devices/julaboFP50.py b/examples/lab_devices/julaboFP50.py new file mode 100644 index 00000000..8cef6190 --- /dev/null +++ b/examples/lab_devices/julaboFP50.py @@ -0,0 +1,17 @@ +from basil.dut import Dut + +dut = Dut('/home/silab/git/basil/examples/lab_devices/julaboFP50_pyserial.yaml') +dut.init() + + +# turn on: +# dut["chiller"].start_chiller(start=True) + +# dut["chiller"].set_temp(15) # set temp + +print("Status: {}".format(dut["chiller"].get_status())) + +# turn off: +# dut["chiller"].stop_chiller() + + diff --git a/examples/lab_devices/julaboFP50_pyserial.yaml b/examples/lab_devices/julaboFP50_pyserial.yaml new file mode 100644 index 00000000..7310350f --- /dev/null +++ b/examples/lab_devices/julaboFP50_pyserial.yaml @@ -0,0 +1,20 @@ +transfer_layer: + - name : Serial + type : Serial + init : + port : /dev/ttyUSB0 + read_termination : "\r\n" + write_termination : "\r\n" + baudrate : 9600 + timeout : 5.0 + parity : "N" ### serial.PARITY_NONE + xonxoff : True # software handshake on + rtscts : False + dsrdtr : False + + +hw_drivers: + - name : chiller + type : julaboFP50 + interface : Serial + From 9435cdb65eb2b3806f5c1700c3784c5bdc443768 Mon Sep 17 00:00:00 2001 From: AntonioT7 <115623462+AntonioT7@users.noreply.github.com> Date: Fri, 2 Dec 2022 14:02:46 +0100 Subject: [PATCH 02/21] Update julabo_FP50.yaml --- basil/HL/julabo_FP50.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/basil/HL/julabo_FP50.yaml b/basil/HL/julabo_FP50.yaml index 50a15e29..62531bab 100644 --- a/basil/HL/julabo_FP50.yaml +++ b/basil/HL/julabo_FP50.yaml @@ -10,4 +10,4 @@ get_version: version # get the version of the device get_status: status # see its status (manual start, remote control, ...) set_power: out_hil_00 # Set the desired maximum cooling power (0% to 100%). Note: Enter the value with a preceding negative sign! This setting is meaningful only for FP cooling machines. on: out_mode_05 1 # start (parameter 1) -off: out_mode_05 0 # stop (parameter 0) \ No newline at end of file +off: out_mode_05 0 # stop (parameter 0) From a5b697895d9c71d4a13a16722174dce1a8795d8a Mon Sep 17 00:00:00 2001 From: AntonioT7 Date: Fri, 2 Dec 2022 15:17:00 +0100 Subject: [PATCH 03/21] new julabo fp50 --- basil/HL/julabo_FP50.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/basil/HL/julabo_FP50.yaml b/basil/HL/julabo_FP50.yaml index 50a15e29..62531bab 100644 --- a/basil/HL/julabo_FP50.yaml +++ b/basil/HL/julabo_FP50.yaml @@ -10,4 +10,4 @@ get_version: version # get the version of the device get_status: status # see its status (manual start, remote control, ...) set_power: out_hil_00 # Set the desired maximum cooling power (0% to 100%). Note: Enter the value with a preceding negative sign! This setting is meaningful only for FP cooling machines. on: out_mode_05 1 # start (parameter 1) -off: out_mode_05 0 # stop (parameter 0) \ No newline at end of file +off: out_mode_05 0 # stop (parameter 0) From 86edb217a7eade5ce58e8a141f3266a9c938240d Mon Sep 17 00:00:00 2001 From: AntonioT7 Date: Fri, 2 Dec 2022 15:24:01 +0100 Subject: [PATCH 04/21] new julabo fp50 --- examples/lab_devices/julaboFP50.py | 4 +--- examples/lab_devices/julaboFP50_pyserial.yaml | 1 - 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/examples/lab_devices/julaboFP50.py b/examples/lab_devices/julaboFP50.py index 8cef6190..c770bec7 100644 --- a/examples/lab_devices/julaboFP50.py +++ b/examples/lab_devices/julaboFP50.py @@ -12,6 +12,4 @@ print("Status: {}".format(dut["chiller"].get_status())) # turn off: -# dut["chiller"].stop_chiller() - - +# dut["chiller"].stop_chiller() \ No newline at end of file diff --git a/examples/lab_devices/julaboFP50_pyserial.yaml b/examples/lab_devices/julaboFP50_pyserial.yaml index 7310350f..239c8457 100644 --- a/examples/lab_devices/julaboFP50_pyserial.yaml +++ b/examples/lab_devices/julaboFP50_pyserial.yaml @@ -17,4 +17,3 @@ hw_drivers: - name : chiller type : julaboFP50 interface : Serial - From 5abeaf24fd05dcb879f86caa482653c3d6760bf3 Mon Sep 17 00:00:00 2001 From: AntonioT7 Date: Fri, 2 Dec 2022 15:39:08 +0100 Subject: [PATCH 05/21] new julabo fp50 --- examples/lab_devices/julaboFP50.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/lab_devices/julaboFP50.py b/examples/lab_devices/julaboFP50.py index c770bec7..2a5f6e78 100644 --- a/examples/lab_devices/julaboFP50.py +++ b/examples/lab_devices/julaboFP50.py @@ -12,4 +12,4 @@ print("Status: {}".format(dut["chiller"].get_status())) # turn off: -# dut["chiller"].stop_chiller() \ No newline at end of file +# dut["chiller"].stop_chiller() From 53411757cd5bfe19a5bfe3b1d90b52732b581176 Mon Sep 17 00:00:00 2001 From: Thomas Senger Date: Wed, 7 Dec 2022 11:01:52 +0100 Subject: [PATCH 06/21] Julabo FP50: update --- basil/HL/julabo_FP50.yaml | 13 ------------- 1 file changed, 13 deletions(-) delete mode 100644 basil/HL/julabo_FP50.yaml diff --git a/basil/HL/julabo_FP50.yaml b/basil/HL/julabo_FP50.yaml deleted file mode 100644 index 62531bab..00000000 --- a/basil/HL/julabo_FP50.yaml +++ /dev/null @@ -1,13 +0,0 @@ -""" -Device description for using the julabo FP50 chiller -set_ function expect a parameter, get_ function return a parameter. -""" - -get_temp: in_sp_00 # get current set temperature -set_temp: out_sp_00 # set the temperature -get_curr_temp: in_pv_00 # get the current bath temperature -get_version: version # get the version of the device -get_status: status # see its status (manual start, remote control, ...) -set_power: out_hil_00 # Set the desired maximum cooling power (0% to 100%). Note: Enter the value with a preceding negative sign! This setting is meaningful only for FP cooling machines. -on: out_mode_05 1 # start (parameter 1) -off: out_mode_05 0 # stop (parameter 0) From 228c248036a21a68c9c06506dbb1b8993cab9957 Mon Sep 17 00:00:00 2001 From: Thomas Senger Date: Wed, 7 Dec 2022 14:17:30 +0100 Subject: [PATCH 07/21] Julabo FP50: update --- basil/HL/julaboFP50.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/basil/HL/julaboFP50.py b/basil/HL/julaboFP50.py index 682749a7..ae6818ea 100644 --- a/basil/HL/julaboFP50.py +++ b/basil/HL/julaboFP50.py @@ -12,7 +12,7 @@ import logging import time -from basil.HL.RegisterHardwareLayer import HardwareLayer +from basil.HL.HardwareLayer import HardwareLayer logger = logging.getLogger(__name__) @@ -23,6 +23,12 @@ class julaboFP50(HardwareLayer): A simple protocol via crossed null modem serial port is used with baud rate of 9600. ''' + Commands = {'get_temp': 'in_sp_00', + 'set_temp': 'out_sp_00', + 'get_curr_temp': 'in_pv_00', + 'get_version': 'version', + 'get_status': 'status'} + def __init__(self, intf, conf): super(julaboFP50, self).__init__(intf, conf) self.pre_time = time.time() From c19f65235d8b63726111cbf98035222c2deeff40 Mon Sep 17 00:00:00 2001 From: Thomas Senger Date: Wed, 7 Dec 2022 14:53:44 +0100 Subject: [PATCH 08/21] Julabo FP50: update --- examples/lab_devices/julaboFP50.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/lab_devices/julaboFP50.py b/examples/lab_devices/julaboFP50.py index 2a5f6e78..b1e5e5cb 100644 --- a/examples/lab_devices/julaboFP50.py +++ b/examples/lab_devices/julaboFP50.py @@ -1,6 +1,6 @@ from basil.dut import Dut -dut = Dut('/home/silab/git/basil/examples/lab_devices/julaboFP50_pyserial.yaml') +dut = Dut('/julaboFP50_pyserial.yaml') dut.init() From 29f0526400e69a66fb67c17b90c0fcc583cef3a9 Mon Sep 17 00:00:00 2001 From: Thomas Senger Date: Thu, 8 Dec 2022 14:37:27 +0100 Subject: [PATCH 09/21] julabo FP50: update --- examples/lab_devices/julaboFP50.py | 4 ++-- examples/lab_devices/julaboFP50_pyserial.yaml | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/examples/lab_devices/julaboFP50.py b/examples/lab_devices/julaboFP50.py index b1e5e5cb..29034468 100644 --- a/examples/lab_devices/julaboFP50.py +++ b/examples/lab_devices/julaboFP50.py @@ -1,11 +1,11 @@ from basil.dut import Dut -dut = Dut('/julaboFP50_pyserial.yaml') +dut = Dut('julaboFP50_pyserial.yaml') dut.init() # turn on: -# dut["chiller"].start_chiller(start=True) +# dut["chiller"].start_chiller() # dut["chiller"].set_temp(15) # set temp diff --git a/examples/lab_devices/julaboFP50_pyserial.yaml b/examples/lab_devices/julaboFP50_pyserial.yaml index 239c8457..d565ea60 100644 --- a/examples/lab_devices/julaboFP50_pyserial.yaml +++ b/examples/lab_devices/julaboFP50_pyserial.yaml @@ -17,3 +17,5 @@ hw_drivers: - name : chiller type : julaboFP50 interface : Serial + init: + device: julabo FP50 From f12de040765d9cd2785fd3efe852db27bee029b8 Mon Sep 17 00:00:00 2001 From: AntonioT7 Date: Thu, 2 Feb 2023 17:05:49 +0100 Subject: [PATCH 10/21] work with serial interface --- basil/HL/julaboFP50.py | 36 +++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/basil/HL/julaboFP50.py b/basil/HL/julaboFP50.py index ae6818ea..c8d152aa 100644 --- a/basil/HL/julaboFP50.py +++ b/basil/HL/julaboFP50.py @@ -21,13 +21,18 @@ class julaboFP50(HardwareLayer): ''' Driver for the Julabo FP50 chiller. A simple protocol via crossed null modem serial port is used with baud rate of 9600. + All commands were taken from JulaboFP50 manual. ''' - Commands = {'get_temp': 'in_sp_00', - 'set_temp': 'out_sp_00', - 'get_curr_temp': 'in_pv_00', - 'get_version': 'version', - 'get_status': 'status'} + CMDS = {'get_temp': 'in_sp_00', + 'set_temp': 'out_sp_00', + 'get_curr_temp': 'in_pv_00', + 'get_version': 'version', + 'get_status': 'status', + 'start': 'out_mode_05 1', + 'stop': 'out_mode_05 0', + 'set_power': 'out_sp_06' + } def __init__(self, intf, conf): super(julaboFP50, self).__init__(intf, conf) @@ -51,24 +56,24 @@ def write(self, cmd): def get_version(self): ''' Read identifier ''' - self.write("version") + self.write(self.CMDS['get_version']) ret = self.read() return ret def start_chiller(self): ''' Start chiller ''' - self.write("out_mode_05 1") + self.write(self.CMDS['start']) def stop_chiller(self): ''' Stop chiller ''' - self.write("out_mode_05 0") + self.write(self.CMDS['stop']) def get_status(self): ''' Get status ''' - self.write("status") + self.write(self.CMDS['get_status']) ret = self.read() logger.debug("status:{:s}".format(ret)) try: @@ -84,18 +89,23 @@ def get_status(self): def get_set_temp(self): '''get the set temperature ''' - self.write("in_sp_00") + self.write(self.CMDS['get_temp']) ret = self.read() return float(ret) def set_temp(self, temp): - '''set the temperature to a value + '''set the temperature ''' - self.write(f"out_sp_00={temp}") + self.write(f"{self.CMDS['set_temp']}={temp}") def get_temp(self): '''get the current temperature in chiller ''' - self.write("in_pv_00") + self.write(self.CMDS['get_curr_temp']) ret = self.read() return float(ret) + + def set_power(self, variable): + '''Set the power for heater/cooler via serial interface (positive value for heating, negative value for cooling) + ''' + self.write(f"{self.CMDS['set_power']}={variable}") From c911aab2d53a34bfed9dd8c4c18c9c00e75a9dc4 Mon Sep 17 00:00:00 2001 From: AntonioT7 Date: Mon, 13 Feb 2023 10:29:03 +0100 Subject: [PATCH 11/21] Improvement on steering the valve in bronkhorst_ELflow --- basil/HL/bronkhorst_elflow.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/basil/HL/bronkhorst_elflow.py b/basil/HL/bronkhorst_elflow.py index d0439c8f..1cbc50d1 100644 --- a/basil/HL/bronkhorst_elflow.py +++ b/basil/HL/bronkhorst_elflow.py @@ -52,6 +52,10 @@ def read(self): return ret def set_setpoint(self, value): + + if not isinstance(value, int): + raise ValueError(f"Given value has to be of type integer, is {type(value)}!") + cmd = [1, 1, 0x21, (value >> 8) & 0xFF, value & 0xFF] self.write(cmd) ret = self.read() From a82e120601da50a538eb3aa928c53bb5555cd14b Mon Sep 17 00:00:00 2001 From: Thomas Senger Date: Tue, 28 Feb 2023 13:36:23 +0100 Subject: [PATCH 12/21] WIP: improve bronkhorst flowmeter implementation --- basil/HL/bronkhorst_elflow.py | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/basil/HL/bronkhorst_elflow.py b/basil/HL/bronkhorst_elflow.py index 1cbc50d1..bb42cec1 100644 --- a/basil/HL/bronkhorst_elflow.py +++ b/basil/HL/bronkhorst_elflow.py @@ -18,6 +18,13 @@ class Bronkhorst_ELFLOW(HardwareLayer): ''' Bronkhorst ELFLOW ''' + CMDS = { + 'get_valve_opening': '06800472417241\r\n', # These bytes will make the flow meter send back the opening + 'measure_flow': 'b":06800401210120\r\n"', # These bytes will measure the gas flow through the valve in % + 'read_max_capacity': '068004014D014D\r\n' # These bytes will read the maximum capacity of the current flow + } + + def __init__(self, intf, conf): self.debug = 0 self.node = "80" @@ -51,6 +58,23 @@ def read(self): ret.append(int(ret_s[5 + 2 * i:5 + 2 * (i + 1)], 16)) return ret + + def get_opening(self): + self._intf.write(self.CMDS['get_valve_opening']) + + def get_flow(self): + self._intf.write(self.CMDS['measure_flow']) + self._intf.readline().decode() + reading = self._intf.readline().decode()[11:-2] + print(reading) + int_flow = int(reading, 16) + print(int_flow) + + + + def get_max_cap(self): + self._intf.write(self.CMDS['read_max_capacity']) + def set_setpoint(self, value): if not isinstance(value, int): @@ -70,6 +94,7 @@ def set_setpoint(self, value): def get_setpoint(self): cmd = [4, 1, 0x21, 1, 0x21] + # 06800401210121\r\n self.write(cmd) ret = self.read() if len(ret) != 5: @@ -88,6 +113,7 @@ def set_control_mode(self, value): 8 valve fully open 20 valve steering (valve=setpoint)""" cmd = [1, 1, 4, value & 0xFF] + # 0580010104xx\r\n where xx self.write(cmd) ret = self.read() if len(ret) != 3: @@ -167,6 +193,7 @@ def get_controller_speed(self): def get_measure(self): cmd = [4, 1, 0x21, 1, 0x20] + # 06800401210120\r\n self.write(cmd) ret = self.read() if len(ret) != 5: @@ -177,3 +204,10 @@ def get_measure(self): else: logger.debug("ELFLOW.get_valve_output() ret error ret=%s" % str(ret)) return -1 + + def get_max_capacity(self): + cmd = [4, 1, 0x4D, 1, 0x4D] + # 068004014D014D\r\n + self.write(cmd) + ret = self.read() + print(ret) From 88457940b51f738a8230b528ea2c6d460a53ac22 Mon Sep 17 00:00:00 2001 From: Thomas Senger Date: Tue, 28 Feb 2023 13:53:44 +0100 Subject: [PATCH 13/21] WIP: add a link to the commads document --- basil/HL/bronkhorst_elflow.py | 1 + 1 file changed, 1 insertion(+) diff --git a/basil/HL/bronkhorst_elflow.py b/basil/HL/bronkhorst_elflow.py index bb42cec1..17cbbf5a 100644 --- a/basil/HL/bronkhorst_elflow.py +++ b/basil/HL/bronkhorst_elflow.py @@ -16,6 +16,7 @@ class Bronkhorst_ELFLOW(HardwareLayer): ''' Bronkhorst ELFLOW + Manual can be found here https://www.bronkhorst.com/getmedia/77a1438f-e547-4a79-95ad-53e81fd38a97/917027-Manual-RS232-interface.pdf ''' CMDS = { From 77eccd1905284099672131a4d07204334b6ab8dc Mon Sep 17 00:00:00 2001 From: Thomas Senger Date: Wed, 8 Mar 2023 14:40:09 +0100 Subject: [PATCH 14/21] WIP: adding commands --- basil/HL/bronkhorst_elflow.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/basil/HL/bronkhorst_elflow.py b/basil/HL/bronkhorst_elflow.py index 17cbbf5a..069496b7 100644 --- a/basil/HL/bronkhorst_elflow.py +++ b/basil/HL/bronkhorst_elflow.py @@ -20,9 +20,10 @@ class Bronkhorst_ELFLOW(HardwareLayer): ''' CMDS = { - 'get_valve_opening': '06800472417241\r\n', # These bytes will make the flow meter send back the opening - 'measure_flow': 'b":06800401210120\r\n"', # These bytes will measure the gas flow through the valve in % - 'read_max_capacity': '068004014D014D\r\n' # These bytes will read the maximum capacity of the current flow + 'get_valve_opening': ':06800472417241\r\n', # These bytes will make the flow meter send back the opening + 'measure_flow': ':06800401210120\r\n', # These bytes will measure the gas flow through the valve in % + 'read_max_capacity': ':068004014D014D\r\n', # These bytes will read the maximum capacity of the current flow + 'read_control_mode': ':06800401040104\r\n' # these bytes will give what control mode is on } @@ -116,7 +117,9 @@ def set_control_mode(self, value): cmd = [1, 1, 4, value & 0xFF] # 0580010104xx\r\n where xx self.write(cmd) + print(cmd) ret = self.read() + print(ret) if len(ret) != 3: logger.debug("ELFLOW.set_setpoint() data lenth error ret=%s" % str(ret)) return -1 @@ -128,6 +131,7 @@ def set_control_mode(self, value): def get_control_mode(self): cmd = [4, 1, 1, 1, 4] + # :06800401040104\r\n self.write(cmd) ret = self.read() if len(ret) != 4: From 9c1f0d16a8cbeb36fc6d12d2022bfbc660ed9cfa Mon Sep 17 00:00:00 2001 From: Thomas Senger Date: Fri, 10 Mar 2023 11:36:07 +0100 Subject: [PATCH 15/21] WIP: delete the functions of get/set control mode written by thirono --- basil/HL/bronkhorst_elflow.py | 41 ++++------------------------------- 1 file changed, 4 insertions(+), 37 deletions(-) diff --git a/basil/HL/bronkhorst_elflow.py b/basil/HL/bronkhorst_elflow.py index 069496b7..5d43b2a6 100644 --- a/basil/HL/bronkhorst_elflow.py +++ b/basil/HL/bronkhorst_elflow.py @@ -6,6 +6,7 @@ # import logging +import time import struct from basil.HL.RegisterHardwareLayer import HardwareLayer @@ -21,9 +22,10 @@ class Bronkhorst_ELFLOW(HardwareLayer): CMDS = { 'get_valve_opening': ':06800472417241\r\n', # These bytes will make the flow meter send back the opening - 'measure_flow': ':06800401210120\r\n', # These bytes will measure the gas flow through the valve in % + 'measure_flow': ':06800401210120\r\n', # These bytes will measure the gas flow through the valve in % 'read_max_capacity': ':068004014D014D\r\n', # These bytes will read the maximum capacity of the current flow - 'read_control_mode': ':06800401040104\r\n' # these bytes will give what control mode is on + 'read_control_mode': ':06800401040104', # these bytes will give what control mode is on + 'set_control_mode': ':0580010104', } @@ -108,41 +110,6 @@ def get_setpoint(self): logger.debug("ELFLOW.set_setpoint() ret error ret=%s" % str(ret)) return -1 - def set_control_mode(self, value): - """ 0 setpoint source RS232 - 3 valve close - 4 freeze valuve out - 8 valve fully open - 20 valve steering (valve=setpoint)""" - cmd = [1, 1, 4, value & 0xFF] - # 0580010104xx\r\n where xx - self.write(cmd) - print(cmd) - ret = self.read() - print(ret) - if len(ret) != 3: - logger.debug("ELFLOW.set_setpoint() data lenth error ret=%s" % str(ret)) - return -1 - elif ret[0] == 0 and ret[1] == 0 and ret[2] == 4: - return 0 - else: - logger.debug("ELFLOW.set_setpoint() ret error ret=%s" % str(ret)) - return -1 - - def get_control_mode(self): - cmd = [4, 1, 1, 1, 4] - # :06800401040104\r\n - self.write(cmd) - ret = self.read() - if len(ret) != 4: - logger.debug("ELFLOW.set_setpoint() data lenth error ret=%s" % str(ret)) - return -1 - elif ret[0] == 2 and ret[1] == cmd[1] and ret[2] == cmd[2]: - return ret[3] - else: - logger.debug("ELFLOW.set_setpoint() ret error ret=%s" % str(ret)) - return -1 - def set_valve_output(self, value): cmd = [1, 114, 0x41, (value >> 24) & 0xFF, (value >> 16) & 0xFF, (value >> 8) & 0xFF, value & 0xFF] self.write(cmd) From 7ccf1c61b029382a95d58b14ace61d2d4c8ddfc4 Mon Sep 17 00:00:00 2001 From: Thomas Senger Date: Fri, 10 Mar 2023 19:03:54 +0100 Subject: [PATCH 16/21] WIP: bring back the functions from thirono for a while --- basil/HL/bronkhorst_elflow.py | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/basil/HL/bronkhorst_elflow.py b/basil/HL/bronkhorst_elflow.py index 5d43b2a6..d4960ac0 100644 --- a/basil/HL/bronkhorst_elflow.py +++ b/basil/HL/bronkhorst_elflow.py @@ -110,6 +110,37 @@ def get_setpoint(self): logger.debug("ELFLOW.set_setpoint() ret error ret=%s" % str(ret)) return -1 + def set_control_mode(self, value): + """ 0 setpoint source RS232 + 3 valve close + 4 freeze valuve out + 8 valve fully open + 20 valve steering (valve=setpoint)""" + cmd = [1, 1, 4, value & 0xFF] + self.write(cmd) + ret = self.read() + if len(ret) != 3: + logger.debug("ELFLOW.set_setpoint() data lenth error ret=%s" % str(ret)) + return -1 + elif ret[0] == 0 and ret[1] == 0 and ret[2] == 4: + return 0 + else: + logger.debug("ELFLOW.set_setpoint() ret error ret=%s" % str(ret)) + return -1 + + def get_control_mode(self): + cmd = [4, 1, 1, 1, 4] + self.write(cmd) + ret = self.read() + if len(ret) != 4: + logger.debug("ELFLOW.set_setpoint() data lenth error ret=%s" % str(ret)) + return -1 + elif ret[0] == 2 and ret[1] == cmd[1] and ret[2] == cmd[2]: + return ret[3] + else: + logger.debug("ELFLOW.set_setpoint() ret error ret=%s" % str(ret)) + return -1 + def set_valve_output(self, value): cmd = [1, 114, 0x41, (value >> 24) & 0xFF, (value >> 16) & 0xFF, (value >> 8) & 0xFF, value & 0xFF] self.write(cmd) From 9aa0e2d5562814a69d383c79a26c09bd06462f2c Mon Sep 17 00:00:00 2001 From: AntonioT7 Date: Mon, 13 Mar 2023 14:04:35 +0100 Subject: [PATCH 17/21] brokhorst valve control and measure N2 flow is ready --- basil/HL/bronkhorst_elflow.py | 224 +++++++++------------------------- 1 file changed, 59 insertions(+), 165 deletions(-) diff --git a/basil/HL/bronkhorst_elflow.py b/basil/HL/bronkhorst_elflow.py index d4960ac0..4e5aac6d 100644 --- a/basil/HL/bronkhorst_elflow.py +++ b/basil/HL/bronkhorst_elflow.py @@ -6,8 +6,8 @@ # import logging -import time import struct +import time from basil.HL.RegisterHardwareLayer import HardwareLayer @@ -17,200 +17,94 @@ class Bronkhorst_ELFLOW(HardwareLayer): ''' Bronkhorst ELFLOW - Manual can be found here https://www.bronkhorst.com/getmedia/77a1438f-e547-4a79-95ad-53e81fd38a97/917027-Manual-RS232-interface.pdf + Manual can be found here: + https://www.bronkhorst.com/getmedia/77a1438f-e547-4a79-95ad-53e81fd38a97/917027-Manual-RS232-interface.pdf ''' CMDS = { - 'get_valve_opening': ':06800472417241\r\n', # These bytes will make the flow meter send back the opening - 'measure_flow': ':06800401210120\r\n', # These bytes will measure the gas flow through the valve in % - 'read_max_capacity': ':068004014D014D\r\n', # These bytes will read the maximum capacity of the current flow - 'read_control_mode': ':06800401040104', # these bytes will give what control mode is on + 'get_measure_flow': ':06800401210120', + 'get_capacity': ':068004014D014D', + 'get_control_mode': ':06800401040104', 'set_control_mode': ':0580010104', + 'set_setpoint': ':0680010121', + 'get_setpoint': ':06800401210121', } - def __init__(self, intf, conf): self.debug = 0 self.node = "80" super(Bronkhorst_ELFLOW, self).__init__(intf, conf) + self.pre_time = time.time() def init(self): super(Bronkhorst_ELFLOW, self).init() def write(self, cmd): - cmd_s = "" - for c in cmd: - cmd_s = cmd_s + "%02X" % c - cmd_s = ":%02X%s%s" % (len(cmd) + 1, self.node, cmd_s) - if self.debug != 0: - logger.debug("ELFLOW.write() %s" % str(cmd_s)) - self._intf.write(cmd_s) + if time.time() - self.pre_time < 1.0: + time.sleep(1.0) + self._intf.write(str(cmd)) + self.pre_time = time.time() def read(self): - ret_s = self._intf.read() - if self.debug != 0: - logger.debug("ELFLOW.read() %s" % str(ret_s)) - if len(ret_s) < 5 or ret_s[0] != ":" or ret_s[3:5] != self.node: - logger.debug("ELFLOW.read() format error ret=%s" % str(ret_s)) - return [] - ret_len = int(ret_s[1:3]) - if ret_len * 2 != len(ret_s[3:-2]): - logger.debug("ELFLOW.read() data lenth error ret=%s" % str(ret_s)) - return [] - ret = [] - for i in range(ret_len - 1): - ret.append(int(ret_s[5 + 2 * i:5 + 2 * (i + 1)], 16)) - return ret - - - def get_opening(self): - self._intf.write(self.CMDS['get_valve_opening']) - - def get_flow(self): - self._intf.write(self.CMDS['measure_flow']) - self._intf.readline().decode() - reading = self._intf.readline().decode()[11:-2] - print(reading) - int_flow = int(reading, 16) - print(int_flow) - - - - def get_max_cap(self): - self._intf.write(self.CMDS['read_max_capacity']) + ret = self._intf.read() + if len(ret) < 2 or ret[-2:] != "\r\n": + logger.warning("read() termination error") + return ret.strip() def set_setpoint(self, value): + """value range from 0 - 32000 + """ if not isinstance(value, int): raise ValueError(f"Given value has to be of type integer, is {type(value)}!") - cmd = [1, 1, 0x21, (value >> 8) & 0xFF, value & 0xFF] - self.write(cmd) + hex_val = hex(value)[2:] # [2:] to remove the 0x from the beginning of the hex number + command = f"{self.CMDS['set_setpoint']}" + f"{hex_val.zfill(2)}" # hex should have at least two digits + self._intf.write(command) ret = self.read() - if len(ret) != 3: - logger.debug("ELFLOW.set_setpoint() data lenth error ret=%s" % str(ret)) - return -1 - elif ret[0] == 0 and ret[1] == 0 and ret[2] == 5: - return 0 - else: - logger.debug("ELFLOW.set_setpoint() ret error ret=%s" % str(ret)) - return -1 + return ret def get_setpoint(self): - cmd = [4, 1, 0x21, 1, 0x21] - # 06800401210121\r\n - self.write(cmd) + self._intf.write(self.CMDS['get_setpoint']) ret = self.read() - if len(ret) != 5: - logger.debug("ELFLOW.set_setpoint() data lenth error ret=%s" % str(ret)) - return -1 - elif ret[0] == 2 and ret[1] == cmd[1] and ret[2] == cmd[2]: - return ((ret[3] << 8) & 0xFF00) | (ret[4] & 0xFF) - else: - logger.debug("ELFLOW.set_setpoint() ret error ret=%s" % str(ret)) - return -1 - - def set_control_mode(self, value): + answer_in_hex = ret[11:] # read from the 11th digits to translate what mode is on + answer = int(answer_in_hex, 16) + return answer + + def set_mode(self, value): """ 0 setpoint source RS232 3 valve close - 4 freeze valuve out + 4 freeze valve out 8 valve fully open - 20 valve steering (valve=setpoint)""" - cmd = [1, 1, 4, value & 0xFF] - self.write(cmd) + 20 valve steering """ + hex_val = hex(value)[2:] # [2:] to remove the 0x from the beginning of the hex number + command = f"{self.CMDS['set_control_mode']}" + f"{hex_val.zfill(2)}" # hex should have at least two digits + self._intf.write(command) ret = self.read() - if len(ret) != 3: - logger.debug("ELFLOW.set_setpoint() data lenth error ret=%s" % str(ret)) - return -1 - elif ret[0] == 0 and ret[1] == 0 and ret[2] == 4: - return 0 - else: - logger.debug("ELFLOW.set_setpoint() ret error ret=%s" % str(ret)) - return -1 - - def get_control_mode(self): - cmd = [4, 1, 1, 1, 4] - self.write(cmd) - ret = self.read() - if len(ret) != 4: - logger.debug("ELFLOW.set_setpoint() data lenth error ret=%s" % str(ret)) - return -1 - elif ret[0] == 2 and ret[1] == cmd[1] and ret[2] == cmd[2]: - return ret[3] - else: - logger.debug("ELFLOW.set_setpoint() ret error ret=%s" % str(ret)) - return -1 - - def set_valve_output(self, value): - cmd = [1, 114, 0x41, (value >> 24) & 0xFF, (value >> 16) & 0xFF, (value >> 8) & 0xFF, value & 0xFF] - self.write(cmd) - ret = self.read() - if len(ret) != 3: - logger.debug("ELFLOW.set_valve_output() data lenth error ret=%s" % str(ret)) - return -1 - elif ret[0] == 0 and ret[1] == 0 and ret[2] == 7: - return 0 - else: - logger.debug("ELFLOW.set_valve_output() ret error ret=%s" % str(ret)) - return -1 - - def get_valve_output(self): - cmd = [4, 114, 0x41, 114, 0x41] - self.write(cmd) - ret = self.read() - if len(ret) != 7: - logger.debug("ELFLOW.set_setpoint() data lenth error ret=%s" % str(ret)) - return -1 - elif ret[0] == 2 and ret[1] == cmd[1] and ret[2] == cmd[2]: - return ((ret[3] << 24) & 0xFF000000) | ((ret[4] << 16) & 0xFF0000) | ((ret[5] << 8) & 0xFF00) | (ret[6] & 0xFF) - else: - logger.debug("ELFLOW.get_valve_output() ret error ret=%s" % str(ret)) - return -1 - - def set_controller_speed(self, value): - value = struct.unpack('> 24) & 0xFF, (value >> 16) & 0xFF, (value >> 8) & 0xFF, value & 0xFF] - self.write(cmd) - ret = self.read() - if len(ret) != 3: - logger.debug("ELFLOW.set_controller_speed() data lenth error ret=%s" % str(ret)) - return -1 - elif ret[0] == 0 and ret[1] == 0 and ret[2] == 7: - return 0 - else: - logger.debug("ELFLOW.set_controller_speed() ret error ret=%s" % str(ret)) - return -1 - - def get_controller_speed(self): - cmd = [4, 114, 0x41, 114, 0x40 + 30] - self.write(cmd) - ret = self.read() - if len(ret) != 7: - logger.debug("ELFLOW.set_setpoint() data lenth error ret=%s" % str(ret)) - return -1 - elif ret[0] == 2 and ret[1] == cmd[1] and ret[2] == cmd[2]: - return struct.unpack('!f', chr(ret[3]) + chr(ret[4]) + chr(ret[5]) + chr(ret[6]))[0] - else: - logger.debug("ELFLOW.get_valve_output() ret error ret=%s" % str(ret)) - return -1 - - def get_measure(self): - cmd = [4, 1, 0x21, 1, 0x20] - # 06800401210120\r\n - self.write(cmd) + return ret + + def get_mode(self): + self._intf.write(self.CMDS['get_control_mode']) ret = self.read() - if len(ret) != 5: - logger.debug("ELFLOW.set_setpoint() data lenth error ret=%s" % str(ret)) - return -1 - elif ret[0] == 2 and ret[1] == cmd[1] and ret[2] == cmd[2]: - return ((ret[3] << 8) & 0xFF00) | (ret[4] & 0xFF) - else: - logger.debug("ELFLOW.get_valve_output() ret error ret=%s" % str(ret)) - return -1 - - def get_max_capacity(self): - cmd = [4, 1, 0x4D, 1, 0x4D] - # 068004014D014D\r\n - self.write(cmd) + answer_in_hex = ret[11:] # read from the 11th digits to translate what mode is on + answer = int(answer_in_hex, 16) + return answer + + def get_flow(self): + """This should give the flow in l/min + """ + + # first get the max capacity in % + self._intf.write(self.CMDS['get_capacity']) ret = self.read() - print(ret) + answer_in_hex = ret[11:] # read from the 11th digits to translate what mode is on + cap_100 = struct.unpack('!f', bytes.fromhex(answer_in_hex))[0] + + # now measure the flow + self._intf.write(self.CMDS['get_measure_flow']) + ret1 = self.read() + answer_in_hex = ret1[11:] # read from the 11th digits to translate what mode is on + answer = int(answer_in_hex, 16) + + val = answer / 32000 * cap_100 + return val From d4c9c8a7610480bff5f728b920a2fbd37c355125 Mon Sep 17 00:00:00 2001 From: AntonioT7 Date: Tue, 14 Mar 2023 15:39:30 +0100 Subject: [PATCH 18/21] just changed the usb port for julabo --- examples/lab_devices/julaboFP50_pyserial.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/lab_devices/julaboFP50_pyserial.yaml b/examples/lab_devices/julaboFP50_pyserial.yaml index d565ea60..f155b599 100644 --- a/examples/lab_devices/julaboFP50_pyserial.yaml +++ b/examples/lab_devices/julaboFP50_pyserial.yaml @@ -2,7 +2,7 @@ transfer_layer: - name : Serial type : Serial init : - port : /dev/ttyUSB0 + port : /dev/ttyUSB5 read_termination : "\r\n" write_termination : "\r\n" baudrate : 9600 From 182e9006d6749b3b95ce763227cbdaef034ed3aa Mon Sep 17 00:00:00 2001 From: AntonioT7 Date: Tue, 14 Mar 2023 15:55:53 +0100 Subject: [PATCH 19/21] corrected some comments --- basil/HL/bronkhorst_elflow.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/basil/HL/bronkhorst_elflow.py b/basil/HL/bronkhorst_elflow.py index 4e5aac6d..7616ea79 100644 --- a/basil/HL/bronkhorst_elflow.py +++ b/basil/HL/bronkhorst_elflow.py @@ -67,7 +67,7 @@ def set_setpoint(self, value): def get_setpoint(self): self._intf.write(self.CMDS['get_setpoint']) ret = self.read() - answer_in_hex = ret[11:] # read from the 11th digits to translate what mode is on + answer_in_hex = ret[11:] # read from the 11th digits to translate what point is set answer = int(answer_in_hex, 16) return answer @@ -97,13 +97,13 @@ def get_flow(self): # first get the max capacity in % self._intf.write(self.CMDS['get_capacity']) ret = self.read() - answer_in_hex = ret[11:] # read from the 11th digits to translate what mode is on + answer_in_hex = ret[11:] # read from the 11th digits to translate what the capacity is cap_100 = struct.unpack('!f', bytes.fromhex(answer_in_hex))[0] # now measure the flow self._intf.write(self.CMDS['get_measure_flow']) ret1 = self.read() - answer_in_hex = ret1[11:] # read from the 11th digits to translate what mode is on + answer_in_hex = ret1[11:] answer = int(answer_in_hex, 16) val = answer / 32000 * cap_100 From 031048e72a18b2e98da849c9734163b5660739d5 Mon Sep 17 00:00:00 2001 From: AntonioT7 Date: Wed, 12 Apr 2023 08:52:28 +0200 Subject: [PATCH 20/21] adjust to the temporary changes in USB-ports --- examples/lab_devices/arduino_ntc_readout.yaml | 2 +- examples/lab_devices/julaboFP50.py | 4 +++- examples/lab_devices/julaboFP50_pyserial.yaml | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/examples/lab_devices/arduino_ntc_readout.yaml b/examples/lab_devices/arduino_ntc_readout.yaml index e86ce1ba..c51924a9 100644 --- a/examples/lab_devices/arduino_ntc_readout.yaml +++ b/examples/lab_devices/arduino_ntc_readout.yaml @@ -2,7 +2,7 @@ transfer_layer: - name : Serial type : Serial init : - port : /dev/ttyUSB1 + port : /dev/ttyUSB2 baudrate : 115200 timeout: 2 read_termination: "\r\n" # Needs to be double-quoted string for YAML to parse this correctly diff --git a/examples/lab_devices/julaboFP50.py b/examples/lab_devices/julaboFP50.py index 29034468..a5aefbf9 100644 --- a/examples/lab_devices/julaboFP50.py +++ b/examples/lab_devices/julaboFP50.py @@ -8,8 +8,10 @@ # dut["chiller"].start_chiller() # dut["chiller"].set_temp(15) # set temp +# dut["chiller"].set_power(0) # set power + print("Status: {}".format(dut["chiller"].get_status())) # turn off: -# dut["chiller"].stop_chiller() +dut["chiller"].stop_chiller() diff --git a/examples/lab_devices/julaboFP50_pyserial.yaml b/examples/lab_devices/julaboFP50_pyserial.yaml index f155b599..3fb801b5 100644 --- a/examples/lab_devices/julaboFP50_pyserial.yaml +++ b/examples/lab_devices/julaboFP50_pyserial.yaml @@ -2,7 +2,7 @@ transfer_layer: - name : Serial type : Serial init : - port : /dev/ttyUSB5 + port : /dev/ttyUSB3 read_termination : "\r\n" write_termination : "\r\n" baudrate : 9600 From acd5d13ceb5feded93ea39a658a32d2e31af59c8 Mon Sep 17 00:00:00 2001 From: AntonioT7 Date: Wed, 12 Apr 2023 11:04:48 +0200 Subject: [PATCH 21/21] to solve the conflict in the pull request #197 --- examples/lab_devices/julaboFP50.py | 4 +--- examples/lab_devices/julaboFP50_pyserial.yaml | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/examples/lab_devices/julaboFP50.py b/examples/lab_devices/julaboFP50.py index a5aefbf9..29034468 100644 --- a/examples/lab_devices/julaboFP50.py +++ b/examples/lab_devices/julaboFP50.py @@ -8,10 +8,8 @@ # dut["chiller"].start_chiller() # dut["chiller"].set_temp(15) # set temp -# dut["chiller"].set_power(0) # set power - print("Status: {}".format(dut["chiller"].get_status())) # turn off: -dut["chiller"].stop_chiller() +# dut["chiller"].stop_chiller() diff --git a/examples/lab_devices/julaboFP50_pyserial.yaml b/examples/lab_devices/julaboFP50_pyserial.yaml index 3fb801b5..d565ea60 100644 --- a/examples/lab_devices/julaboFP50_pyserial.yaml +++ b/examples/lab_devices/julaboFP50_pyserial.yaml @@ -2,7 +2,7 @@ transfer_layer: - name : Serial type : Serial init : - port : /dev/ttyUSB3 + port : /dev/ttyUSB0 read_termination : "\r\n" write_termination : "\r\n" baudrate : 9600