1.3. Python Coding for TCLab#
The following cells demonstrate the use of the TCLab hardware. Open a new Jupyter notebook on your laptop, connect the TCLab hardware to the USB port of your laptop, then create and run cells as you follow along in this notebook.
1.3.1. Creating a TCLab instance#
Once installed, the tclab
package can be imported into Python and an instance created with the Python statements
from tclab import TCLab
lab = TCLab()
# do something
lab.close()
TCLab() attempts to find a device connected to a serial port and return a connection. An error is generated if no device is found. The connection must be closed when no longer in use.
from tclab import TCLab
lab = TCLab()
# do something
lab.close()
TCLab version 0.4.10dev
Arduino Leonardo connected on port /dev/cu.usbmodem143101 at 115200 baud.
TCLab Firmware 2.0.1 Arduino Leonardo/Micro.
TCLab disconnected successfully.
1.3.2. Using the LED#
The following cell demonstrates the process, and uses the tclab LED()
function to flash the LED on the Temperature Control Lab for a period of 10 seconds at a 100% brightness level.
from tclab import TCLab
lab = TCLab()
lab.LED(50)
lab.close()
TCLab version 0.4.10dev
Arduino Leonardo connected on port /dev/cu.usbmodem143101 at 115200 baud.
TCLab Firmware 2.0.1 Arduino Leonardo/Micro.
TCLab disconnected successfully.
1.3.3. Using TCLab and Python’s with
statement#
The Python with
statement provides a convenient means of setting up and closing a connection to the Temperature Control Laboratory. In particular, the with statement establishes a context where a tclab instance is created, assigned to a variable, and automatically closed upon completion. The with
statement is the preferred way to connect the Temperature Control Laboratory for most uses.
from tclab import TCLab
with TCLab() as lab:
lab.LED(100)
TCLab version 0.4.10dev
Arduino Leonardo connected on port /dev/cu.usbmodem143101 at 115200 baud.
TCLab Firmware 2.0.1 Arduino Leonardo/Micro.
TCLab disconnected successfully.
1.3.4. Reading Temperatures#
Once a tclab instance is created and connected to a device the temperature sensors are acccessed with the attributes .T1
and .T2
. Given an instance named lab
, the temperatures are accessed as
T1 = lab.T1
T2 = lab.T2
Note that lab.T1
and lab.T2
are read-only properties. Attempt to assign a value will return a Python error.
from tclab import TCLab
with TCLab() as lab:
T1 = lab.T1
T2 = lab.T2
print(f"Temperature 1: {T1:0.2f} C")
print(f"Temperature 2: {T2:0.2f} C")
TCLab version 0.4.10dev
Arduino Leonardo connected on port /dev/cu.usbmodem143101 at 115200 baud.
TCLab Firmware 2.0.1 Arduino Leonardo/Micro.
Temperature 1: 22.83 C
Temperature 2: 21.86 C
TCLab disconnected successfully.
1.3.5. Setting Heater Power#
1.3.5.1. Setting maximum power with .P1
and .P2
#
Heater power is specified as a percentage of the maximum power available at each heater. The maximum power to each heater is determined by setting parameters .P1
and .P2
to number in the range 0 and 255. The default settings are
lab.P1 = 200
lab.P2 = 100
Based on laboratory measurements, the power delivered to each heater is approximately 14.5 mW per unit increase in .P1
and .P2
. For heater 1 at the default setting of 200, the power is
For heater 2 at the default setting of 100, the power is
Note that the power delivered to the heaters for constant .P1
and .P2
is temperature dependent, and there will be some variation among units.
The default values for .P1
and .P2
were chosen to avoid unnecessarily high temperatures, and to include an asymmetric response between the two heaters.
from tclab import TCLab
with TCLab() as lab:
P1 = lab.P1
P2 = lab.P2
print(f"The maximum power of heater 1 is set to {P1:.0f} corresponding to {P1*0.0145:.2f} watts.")
print(f"The maximum power of heater 1 is set to {P2:.0f} corresponding to {P2*0.0145:.2f} watts.")
TCLab version 0.4.10dev
Arduino Leonardo connected on port /dev/cu.usbmodem143101 at 115200 baud.
TCLab Firmware 2.0.1 Arduino Leonardo/Micro.
The maximum power of heater 1 is set to 200 corresponding to 2.90 watts.
The maximum power of heater 1 is set to 100 corresponding to 1.45 watts.
TCLab disconnected successfully.
1.3.5.2. Setting heater power with .Q1()
and .Q2()
#
For legacy reasons, there are two ways to set the percentage of maximum power delivered to the heaters. The first way is to the functions.Q1()
and .Q2()
of a TCLab
instance. For example, both heaters can be set to 100% power with the functions
lab = TCLab()
lab.Q1(100)
lab.Q2(100)
The device firmware limits the heaters to a range of 0 to 100%. The current settiing may be accessed via
Q1 = lab.Q1()
Q2 = lab.Q2()
The LED on the temperature control laboratory will turns bright when either heater is on. Closing the TCLab instance turns the heaters off.
from tclab import TCLab
import time
with TCLab() as lab:
print(f"Starting Temperature 1: {lab.T1:0.2f} C")
print(f"Starting Temperature 2: {lab.T2:0.2f} C")
lab.Q1(100)
lab.Q2(100)
print(f"Set Heater 1: {lab.Q1()} %")
print(f"Set Heater 2: {lab.Q2()} %")
t_heat = 30
print(f"Heat for {t_heat} seconds")
time.sleep(t_heat)
print("Turn Heaters Off")
lab.Q1(0)
lab.Q2(0)
print("Set Heater 1:", lab.Q1(), "%")
print("Set Heater 2:", lab.Q2(), "%")
print(f"Final Temperature 1: {lab.T1:0.2f} C")
print(f"Final Temperature 2: {lab.T2:0.2f} C")
TCLab version 0.4.10dev
Arduino Leonardo connected on port /dev/cu.usbmodem143101 at 115200 baud.
TCLab Firmware 2.0.1 Arduino Leonardo/Micro.
Starting Temperature 1: 22.83 C
Starting Temperature 2: 21.86 C
Set Heater 1: 100.0 %
Set Heater 2: 100.0 %
Heat for 30 seconds
Turn Heaters Off
Set Heater 1: 0.0 %
Set Heater 2: 0.0 %
Final Temperature 1: 26.38 C
Final Temperature 2: 24.12 C
TCLab disconnected successfully.
1.3.5.3. Setting heater power with .U1
and .U2
#
Alternatively, the percentage of maximum power delivered to the heaters can be set by assigning value to the .U1
and .U2
attributes of a TCLab
instances. Getting the value of .U1
and .U2
retrieves the current settings.
lab = TCLab()
print('Setting power levels on heaters 1 and 2')
lab.U1 = 50
lab.U2 = 25
print('Current power level on Heater 1 is: ', lab.U1, '%')
print('Current power level on Heater 1 is: ', lab.U2, '%')
lab.close()
TCLab version 0.4.10dev
Arduino Leonardo connected on port /dev/cu.usbmodem143101 at 115200 baud.
TCLab Firmware 2.0.1 Arduino Leonardo/Micro.
Setting power levels on heaters 1 and 2
Current power level on Heater 1 is: 50.0 %
Current power level on Heater 1 is: 25.0 %
TCLab disconnected successfully.
1.3.6. Synchronizing with Real Time using clock
#
The tclab
module includes clock
for synchronizing calculations with real time. clock(t_period, t_step)
generates a sequence of evenly spaced time step over a periodt_period
seconds that are t_step
seconds apart. If t_step
is omitted then the default time step is set to 1 second.
from tclab import clock
t_period = 6
t_step = 2
for t in clock(t_period, t_step):
print(t, "sec.")
0 sec.
2.0 sec.
4.0 sec.
6.01 sec.
There are some considerations to keep in mind when using clock
. Most important, by its nature Python is not a real-time environment. clock
makes a best effort to stay in sync with evenly spaced ticks of the real time clock. If, for some reason, the loop falls behind the real time clock, then the generator will skip over the event to get back in sync with the real time clock. Thus the total number of iterations may be less than expected. This behavior is demonstrated in the following cell.
from tclab import TCLab, clock
import time
t_period = 12
t_step = 2
for t in clock(t_period, t_step):
print(t, "sec.")
# insert a long time out between 3 and 5 seconds into the event loop
if (t > 3) and (t < 5):
time.sleep(2.2)
0 sec.
2.0 sec.
4.0 sec.
8.0 sec.
10.0 sec.
12.0 sec.
1.3.6.1. Using clock
with TCLab#
The following cell demonstrates use of clock
to perform a short experiment.
from tclab import TCLab, clock
# length of the experiment in seconds
t_period = 20
with TCLab() as lab:
# turn heaters on to 100%
lab.Q1(100)
lab.Q2(100)
print(f"Set Heater 1 to {lab.Q1():.1f} %")
print(f"Set Heater 2 to {lab.Q2():.1f} %")
# print temperatures each second for tperiod seconds
for t in clock(t_period):
print(f"{t:5.1f} sec: T1 = {lab.T1:4.1f} C T2 = {lab.T2:4.1f} C")
TCLab version 0.4.10dev
Arduino Leonardo connected on port /dev/cu.usbmodem143101 at 115200 baud.
TCLab Firmware 2.0.1 Arduino Leonardo/Micro.
Set Heater 1 to 100.0 %
Set Heater 2 to 100.0 %
0.0 sec: T1 = 29.3 C T2 = 26.8 C
1.0 sec: T1 = 29.3 C T2 = 26.8 C
2.0 sec: T1 = 29.3 C T2 = 27.1 C
3.0 sec: T1 = 29.3 C T2 = 27.0 C
4.0 sec: T1 = 29.2 C T2 = 27.1 C
5.0 sec: T1 = 29.3 C T2 = 27.1 C
6.0 sec: T1 = 29.3 C T2 = 26.8 C
7.0 sec: T1 = 29.3 C T2 = 26.8 C
8.0 sec: T1 = 29.3 C T2 = 26.9 C
9.0 sec: T1 = 29.3 C T2 = 27.2 C
10.0 sec: T1 = 29.3 C T2 = 27.1 C
11.0 sec: T1 = 29.3 C T2 = 27.1 C
12.0 sec: T1 = 29.6 C T2 = 27.1 C
13.0 sec: T1 = 29.6 C T2 = 27.2 C
14.0 sec: T1 = 29.6 C T2 = 27.3 C
15.0 sec: T1 = 29.7 C T2 = 27.5 C
16.0 sec: T1 = 29.9 C T2 = 27.7 C
17.0 sec: T1 = 29.9 C T2 = 27.7 C
18.0 sec: T1 = 30.2 C T2 = 27.4 C
19.0 sec: T1 = 30.2 C T2 = 27.9 C
20.0 sec: T1 = 30.6 C T2 = 28.0 C
TCLab disconnected successfully.
1.3.7. The TCLab Historian
#
The Historian
class provides means for logging process data to a database.
Given a list sources
of data sources and methods to access the data, Historian(sources)
creates an historian that logs data to database on each call to .update()
. Given an instance lab
of a TCLab object, lab.sources
is a default list of data sources and methods for logging temperatures lab.T1
and lab.T2
and power settings lab.U1
and lab.U2
.
lab = TCLab()
h = Historian(lab.sources)
The historian automatically initializes a database to log the process data. The database is updated by issuing a command
h.update(t)
where t
is variable containing the current time.
To demonstrate, the following cell logs 10 seconds of data with time varying power level applied to heater 1. When the experiment is over, h.to_csv
saves the data to a file that be imported in python or a spreadsheet application.
from tclab import TCLab, clock, Historian
with TCLab() as lab:
h = Historian(lab.sources)
for t in clock(10):
lab.Q1(100 if t <= 5 else 0)
h.update(t)
h.to_csv('data.csv')
TCLab version 0.4.10dev
Arduino Leonardo connected on port /dev/cu.usbmodem143101 at 115200 baud.
TCLab Firmware 2.0.1 Arduino Leonardo/Micro.
TCLab disconnected successfully.
Once saved, data can be read and plotted using the Pandas Data Analysis Library as demonstrated in this cell.
%matplotlib inline
import pandas as pd
data = pd.read_csv('data.csv')
data.index = data['Time']
print(data)
data[['Q1', 'Q2']].plot(grid=True)
Time T1 T2 Q1 Q2
Time
0.00 0.00 33.692 29.857 100.0 0.0
1.00 1.00 33.789 29.922 100.0 0.0
2.00 2.00 33.757 29.922 100.0 0.0
3.01 3.01 33.789 29.922 100.0 0.0
4.00 4.00 33.789 29.890 100.0 0.0
5.00 5.00 34.111 29.922 100.0 0.0
6.00 6.00 34.111 29.922 0.0 0.0
7.00 7.00 34.111 29.922 0.0 0.0
8.00 8.00 34.176 30.051 0.0 0.0
9.00 9.00 34.434 30.212 0.0 0.0
10.00 10.00 34.434 30.212 0.0 0.0
<AxesSubplot:xlabel='Time'>
1.3.8. The TCLab Plotter
#
The Plotter
class adds a real time plotting of experimental data. A plotter is created from an instance of an historian as follows
h = Historian(lab.sources)
p = Plotter(h)
Updating the plotter also updates the associated historian.
p.update(t)
The following example shows how this works.
%matplotlib inline
import matplotlib.pyplot as plt
from tclab import TCLab, clock, Historian, Plotter
with TCLab() as lab:
h = Historian(lab.sources)
p = Plotter(h, 10)
for t in clock(10):
lab.Q1(100 if t <= 5 else 0)
p.update(t)
h.to_csv('data.csv')
TCLab disconnected successfully.
1.3.9. Using TCLab Offline#
The tclab
library includes a simulation capability. This is useful for circumstances when it isn’t possible to access the hardware. The followinig cell demonstrated the use of setup
to use the library in simulation mode. The argument connected
is set to True
if the hardware is connected, otherwise False
. Simulation mode allows the use of the speedup
parameter to run experiments at some multiple of real time.
%matplotlib inline
from tclab import clock, setup, Historian, Plotter
t_period = 120
TCLab = setup(connected=False, speedup=20)
with TCLab() as lab:
h = Historian(lab.sources)
p = Plotter(h, t_period)
for t in clock(t_period):
lab.Q1(100 if t % 20 <= 5 else 0)
p.update(t)
TCLab Model disconnected successfully.