1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
|
"""""
Code for monitoring and controlling temperature in the Maxwell FT200 controller using the Modbus RS485 protocol
@author: Lois Orosa
"""""
import minimalmodbus as mm, serial, time
import time
import os
import sys
import pathlib
class FT200:
"""
Controls and monitors the Maxwell FT200 tempoerature controller
"""
READ_ERROR = -999
WRITE_ERROR = -998
def __init__(self, _baud=9600, _ft200_addr=1, _temp_tolerance=2):
self.baud = _baud
self.write_reg = 5 # Write register
self.read_reg = 0 # Read register
self.ft200_addr = _ft200_addr # Address of the device (by default is 1)
self.temp_tolerance = _temp_tolerance # Temperature tolerance. By default, we consider that we reach the target value if the measured value is within +-0.2C
try:
self.device = self.findDevice() # Get the USB-RS485 device
print("USB-RS485 Device: "+str(self.device))
self.instrument = mm.Instrument(self.device , 3 , debug = False)
self.instrument.serial.baudrate = self.baud
self.instrument.address = self.ft200_addr
self.instrument.serial.timeout = 1
self.instrument.serial.parity = serial.PARITY_NONE
self.instrument.mode = mm.MODE_RTU
print("Device "+self.device+": conected")
except:
raise
# Automatically find the USB-RS485 Device
def findDevice(self):
'''
Find the USB-RS485 device
This function might raise two exceptions:
-> NameError: There is more than 1 USB-RS485 device, or other USB device has a similar name as the USB-RS485 device
-> IOError: Device not found.
'''
DEVICENAME = "1a86_USB"
name = ''
while True:
path = pathlib.Path(__file__).parent.absolute()
f = os.popen(str(path)+"/usb_dev_path.sh")
for device in f:
if DEVICENAME in device:
if name == '':
name = device.split()[0]
else:
raise NameError("There are at least two USB devices whose name contains "+str(DEVICENAME))
if name == '':
raise IOError("Device not found.")
return name
# Read Temperature from FT200
# The output value has 1 decimal, and it is multiplied by 10
# E.g., data= 102 represents a temperature of 10.2C
def readTemp(self):
try:
data = self.instrument.read_register(self.read_reg, functioncode=3)
return data
except IOError:
print("Failed to read from instrument")
return self.READ_ERROR
# Check if the temperature reached a value
# The input value has 1 decimal, and it is multiplied by 10
# E.g., data= 102 represents a temperature of 10.2C
def isTemp(self, temperature):
try:
data = self.instrument.read_register(self.read_reg, functioncode=3)
if data >= (temperature-self.temp_tolerance) and data <= (temperature+self.temp_tolerance):
return True
else:
return False
except IOError:
print("Failed to read from instrument")
return False
# Set Temperature FT200
# The value should be a integer, and it should be the temperature value with 1 decimal multiplied by 10
# E.g., value= 102 represents a temperature of 10.2C
def setTemp(self, value):
try:
self.instrument.write_register(self.write_reg, value, functioncode=6)
except IOError:
print("Failed to write to instrument")
return self.WRITE_ERROR
return 0
# Set the temperature and wait for the temperature to be stable
# Optimized version that reach the target temperature earlier
# The value should be a integer, and it should be the temperature value with 1 decimal multiplied by 10
# E.g., value= 102 represents a temperature of 10.2C
def autoSetAndWait(self, temperature, debug = False):
acceleration_factor = 5
stability = 10 # Iterations that the temperature needs to be stable
time_sleep = 1 # 1 second wait per loop iteration
stable_count = stability # Counter for taking into account the stability of the temperature
stable_margin = 20 # We do not change the set temperature if we are within 2C from the target
optTemp = temperature
self.setTemp(optTemp) # Set the temperature
curTemp = self.readTemp() # Read the temperature
if debug:
print("[TEMPERATURE] current: "+str(curTemp/10.0)+", goal: "+str(temperature/10.0)+", programmed: "+str(optTemp/10.0))
while (((curTemp > (temperature + self.temp_tolerance)) or (curTemp < (temperature - self.temp_tolerance))) or (stable_count!=0)):
if debug:
print("[TEMPERATURE] current: "+str(curTemp/10.0)+", goal: "+str(temperature/10.0)+", programmed: "+str(optTemp/10.0)+", stable_count: "+str(stable_count))
prev_optTemp = optTemp
if (temperature - curTemp) > 0: #(stable_margin): # If we are far away more than 2C
optTemp = temperature + (temperature - curTemp)*acceleration_factor # Optimization to accelerate convergence
else:
optTemp = temperature
if optTemp != prev_optTemp:
self.setTemp(optTemp) # Set temperature only if different from the previous iteration
time.sleep(time_sleep) # WAit for a while
curTemp = self.readTemp() # Read the temperature
while (curTemp == self.READ_ERROR): # If there is an error, read again
curTemp = self.readTemp()
# Five iterations in the range
if (curTemp > (temperature + self.temp_tolerance)) or (curTemp < (temperature - self.temp_tolerance)):
stable_count = stability
else:
stable_count -= 1 # The temperature has to remain stable for a while
def autoSetAndWait_2(self, temperature, debug = False):
acceleration_factor = 150
stability = 10 # Iterations that the temperature needs to be stable
time_sleep = 1 # 1 second wait per loop iteration
stable_count = stability # Counter for taking into account the stability of the temperature
stable_margin = 5 # We do not change the set temperature if we are within 2C from the target
optTemp = temperature
self.setTemp(optTemp) # Set the temperature
curTemp = self.readTemp() # Read the temperature
if debug:
print("[TEMPERATURE] current: "+str(curTemp/10.0)+", goal: "+str(temperature/10.0)+", programmed: "+str(optTemp/10.0))
while (((curTemp > (temperature + self.temp_tolerance)) or (curTemp < (temperature - self.temp_tolerance))) or (stable_count!=0)):
if debug:
print("[TEMPERATURE] current: "+str(curTemp/10.0)+", goal: "+str(temperature/10.0)+", programmed: "+str(optTemp/10.0)+", stable_count: "+str(stable_count))
prev_optTemp = optTemp
if abs(temperature - curTemp) > (stable_margin): # If we are far away more than 2C
if temperature > curTemp:
optTemp = temperature + acceleration_factor # Optimization to accelerate convergence
else:
optTemp = temperature - acceleration_factor # Optimization to accelerate convergence
else:
optTemp = temperature
time.sleep(time_sleep) # WAit for a while
curTemp = self.readTemp() # Read the temperature
while (curTemp == self.READ_ERROR): # If there is an error, read again
curTemp = self.readTemp()
# Five iterations in the range
if (curTemp > (temperature + self.temp_tolerance)) or (curTemp < (temperature - self.temp_tolerance)):
stable_count = stability
else:
stable_count -= 1 # The temperature has to remain stable for a while
if __name__ == '__main__':
## Example of how to use the FT200 class
try:
tc = FT200()
except Exception as error:
print("[ERROR] "+ repr(error))
sys.exit(0)
# Temperature
value = int(sys.argv[1]) * 10
print(value)
print(tc.readTemp())
tc.autoSetAndWait(value,True)
|