Readme updated, sketch added and PDFs

main
parent d600ad7808
commit 48224a88bc

@ -1,37 +1,110 @@
# Introduction # Introduction
The temperature control lab is an application of feedback control with an Arduino, an LED, two heaters, and two temperature sensors that is mainly based in the `APMonitor TCLab` project. The heater power output is adjusted to maintain a desired temperature setpoint. Thermal energy from the heater is transferred by conduction, convection, and radiation (phenomena) to the temperature sensor. Heat is also transferred away from the device to the surroundings by the heat-sink. The Temperature Control Laboratory (TCLab) is an application of feedback control with an Arduino, an LED, two heaters, and two temperature sensors that are mainly based on the `APMonitor TCLab` project by Jeffrey Kantor and Carl Sandrock.
This TCLab consists of three main parts: hardware, Arduino sketch, and the `TCLab` library.
**The following guide provides step-by-step instructions to design and build from scratch your own TCLab version that can communicate with Python and Jupyter Notebook.**
## TCLab hardware
The TCLab is a modular, portable, and inexpensive solution for hands-on process control learning. The heat output produced by the transistor is adjusted by modulating (PWM) the current flow to each of the two devices. Then, thermistors measure the temperatures by the Arduino's ADCs.
The energy from the transistor output is transferred by conduction and convection to the temperature sensor. Heat transfer dynamics provide rich opportunities to implement single and multivariable control systems, modeling, and system identification applications. The TClab is integrated into a small PCB, which can be mounted to any Arduino or Arduino-compatible microcontroller.
The next Figure shows the TCLab version distributed by Jeffrey Kantor and Carl Sandrock.
![](http://apmonitor.com/pdc/uploads/Main/tclab_transparent.png) ![](http://apmonitor.com/pdc/uploads/Main/tclab_transparent.png)
This project is a resource for model identification, controller development, and machine learning applications. It is a pocket-sized lab with software in Python, MATLAB, and Simulink for the purpose of reinforcing control theory for students. The device is a resource for model identification, controller development, and machine learning applications. It is a pocket-sized lab with Python software for the purpose of reinforcing control theory for students.
# Portable Temperature Control Lab for Learning Process Control
This lab teaches principles of system dynamics and control. In particular, this lab reinforces: ### TCLab General Schematic
- Dynamic modeling with balance equations Below is the TCLab main schematic to attach to the Arduino UNO board.
- The difference between manual and automatic control
- Step tests to generate dynamic data
- Fitting dynamic data to a First Order Plus Dead Time (FOPDT) model
- Obtaining parameters for PID control from standard tuning rules
- Tuning the PID controller to improve performance
![](./schematic.png)
![](http://apmonitor.com/pdc/uploads/Main/tclab_schematic.png) The board considers the following components:
| Quantity | Description | Value | Package | Notes |
|----------|---------------|----------|------------|-------|
| 2 | TIP31C | | TO-220 | |
| 3 | Resistance | 470 Ohms | 1206 | |
| 2 | TMP36GT | | TO-92 | |
| 1 | LED | | 1206 | |
| 1 | Barrel jack | | | |
| 1 | 10 pins 0.1" | | pin header | |
| 2 | 8 pins 0.1 in | | pin header | |
| 1 | 6 pins 0.1 in | | pin header | |
You will find the complete project with the PCB layout in the open project at [Upverter]().
**The TIP31C and TMP36 data-sheets are in this repository**
## Arduino Sketch
The Arduino Sketch (TCLab sketch) is a set of methods that supports the Temperature Control Lab when downloaded and installed on a compatible Arduino device. The sketch is used in conjunction with the compatible Python library `TCLab` for programmable control of the Temperature Control Lab with Python.
### Hardware setup
1. Plug the Temperature Control Laboratory board in an Arduino UNO or Leonardo. Connect your computer to the Arduino via the USB connection. Plug the DC power adapter into the wall and attach it to the power input to the TCLab board.
2. Install Arduino Drivers if needed. For most users, there will be no need. If you are using Windows 10, the Arduino board should connect with no additional drivers. Mac OS users may need to install a serial driver for Arduino Uno clones. A suitable driver can be found [here](https://github.com/adrianmihalko/ch340g-ch34g-ch34x-mac-os-x-driver) for clones using the CH340G, CH34G or CH34X chipset.
3. Install Arduino Firmware:
* Download and install the Arduino IDE application.
* Download the file TCLab-sketch.ino located in this repository in the folder with the same name.
* Open the Arduino IDE application. Select the Arduino board type from `Tools -> Board -> Arduino Board -> Arduino Uno` or your compatible board, and finally verify the port connection.
* Compile and upload `TCLab-sketch.ino`
4. Test
To confirm the board's proper operation, use the serial monitor (located under the tools menu of the Arduino IDE). Select serial monitor, set the baud rate to 9600, and line endings to 'newline.' If the firmware is operating correctly, enter the command
```
LED 100
```
will cause the LED to flash at 100% power for 10 seconds.
## TCLab library
First, install the Python TCLab library by using:
```
pip3 install tclab
```
then open a Python IDE or execute the next code in Jupyter Notebook.
```
import tclab
with tclab.TCLab() as lab:
print(lab.T1)
```
if everything was done properly, you should receive a message back indicating the temperature of transistor 1 `T1`:
```
Connecting to TCLab
TCLab Firmware Version 1.2.1 on NHduino connected to port XXXX
21.54
TCLab disconnected successfully.
```
---
# Main project objective # Main project objective
The `TC-Lab` project will be used for the students as a portable temperature controller system to implement several kind of controllers. Thus, the student should develop the next tasks to reach the final goal (main objective): The `TC-Lab` project will be used for the students as a portable temperature controller system to implement several kinds of controllers. Thus, the student should develop the next tasks to reach the final goal (main objective):
- Develop the basic schematic - Develop the basic schematic
- Develop the PCB for the `TC-Lab` - Develop the PCB for the `TC-Lab`
- Test the `TC-Lab` in the Arduino platform - Test the `TC-Lab` in the Arduino platform
- Acquire temperature data from heater - Acquire temperature data from the heaters
- Develop a regressor and a classifier - Develop a regressor and a classifier
![](http://apmonitor.com/pdc/uploads/Main/tclab_schematic.png)
![](./tclab-block.png)
![](./pcb.png) ![](./pcb.png)

@ -0,0 +1,358 @@
/*
TCLab Temperature Control Lab Firmware
Jeffrey Kantor, Bill Tubbs, John Hedengren, Shawn Summey
February 2021
This firmware provides a high level interface to the Temperature Control Lab. The
firmware scans the serial port for commands. Commands are case-insensitive. Any
unrecognized command results in sleep model. Each command returns a result string.
A software restart. Returns "Start".
LED float set LED to float for 10 sec. range 0 to 100. Returns actual float
P1 float set pwm limit on heater 1, range 0 to 255. Default 200. Returns P1.
P2 float set pwm limit on heater 2, range 0 to 255. Default 100. Returns P2.
Q1 float set Heater 1, range 0 to 100. Returns value of Q1.
Q2 float set Heater 2, range 0 to 100. Returns value of Q2.
Q1B float set Heater 1, range 0 to 100. Returns value of Q1 as a 32-bit float.
Q2B float set Heater 2, range 0 to 100. Returns value of Q2 as a 32-bit float.
R1 get value of Heater 1, range 0 to 100
R2 get value of Heater 2, range 0 to 100
SCAN get values T1 T2 Q1 Q1 in line delimited values
T1 get Temperature T1. Returns value of T1 in °C.
T2 get Temperature T2. Returns value of T2 in °C.
T1B get Temperature T1. Returns value of T1 in °C as a 32-bit float.
T2B get Temperature T2. Returns value of T2 in °C as a 32-bit float.
VER get firmware version string
X stop, enter sleep mode. Returns "Stop"
Limits on the heater power can be configured with the constants below.
Status is indicated by LED1 on the Temperature Control Lab. Status conditions are:
LED1 LED1
Brightness State
---------- -----
dim steady Normal operation, heaters off
bright steady Normal operation, heaters on
dim blinking High temperature alarm on, heaters off
bright blinking High temperature alarm on, heaters on
The Temperature Control Lab shuts down the heaters if it receives no host commands
during a timeout period (configure below), receives an "X" command, or receives
an unrecognized command from the host.
Constants are used to configure the firmware.
Changelog ordered by Semantic Version
1.0.1 first version included in the tclab package
1.1.0 added R1 and R2 commands to read current heater values
changed heater values to units of percent of full power
added P1 and P2 commands to set heater power limits
changed readCommand to avoid busy states
changed simplified LED status model
1.2.0 added LED command
1.2.1 fixed reset heater values on close
added version history
1.2.2 changed version string for better display by TCLab
1.2.3 changed baudrate to from 9600 to 115200
1.3.0 added SCAN function
added board type in version string
1.4.0 changed Q1 and Q2 to float from int
1.4.1 fixed missing Serial.flush() at end of command loop
1.4.2 fixed bug with X command
1.4.3 deprecated use of Arduino IDE Version < 1.0.0
1.5.0 removed webusb
1.6.0 changed temperature to average 10 measurements to reduce noise
2.0.0 added binary communications.
added T1B and T2B commands return 32-bit float
added Q1B and Q2B commands return 32-bit float confirmation of heater setting
added calculation to use 1.75 AREF to match TMP36 voltage range
2.0.1 added updates to Notre Dame and BYU versions of this firmware
changed version history to standard change log practices
*/
#include "Arduino.h"
// determine board type
#if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168__)
String boardType = "Arduino Uno";
#elif defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega16U4__)
String boardType = "Arduino Leonardo/Micro";
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
String boardType = "Arduino Mega";
#else
String boardType = "Unknown board";
#endif
// Enable debugging output
const bool DEBUG = false;
// constants
const String vers = "2.0.1"; // version of this firmware
const long baud = 115200; // serial baud rate
const char sp = ' '; // command separator
const char nl = '\n'; // command terminator
// pin numbers corresponding to signals on the TC Lab Shield
const int pinT1 = 0; // T1
const int pinT2 = 2; // T2
const int pinQ1 = 3; // Q1
const int pinQ2 = 5; // Q2
const int pinLED1 = 9; // LED1
// temperature alarm limits
const int limT1 = 50; // T1 high alarm (°C)
const int limT2 = 50; // T2 high alarm (°C)
// LED1 levels
const int hiLED = 60; // hi LED
const int loLED = hiLED/16; // lo LED
// global variables
char Buffer[64]; // buffer for parsing serial input
int buffer_index = 0; // index for Buffer
String cmd; // command
float val; // command value
int ledStatus; // 1: loLED
// 2: hiLED
// 3: loLED blink
// 4: hiLED blink
long ledTimeout = 0; // when to return LED to normal operation
float LED = 100; // LED override brightness
float P1 = 200; // heater 1 power limit in units of pwm. Range 0 to 255
float P2 = 100; // heater 2 power limit in units in pwm, range 0 to 255
float Q1 = 0; // last value written to heater 1 in units of percent
float Q2 = 0; // last value written to heater 2 in units of percent
int alarmStatus; // hi temperature alarm status
boolean newData = false; // boolean flag indicating new command
int n = 10; // number of samples for each temperature measurement
void readCommand() {
while (Serial && (Serial.available() > 0) && (newData == false)) {
int byte = Serial.read();
if ((byte != '\r') && (byte != nl) && (buffer_index < 64)) {
Buffer[buffer_index] = byte;
buffer_index++;
}
else {
newData = true;
}
}
}
// for debugging with the serial monitor in Arduino IDE
void echoCommand() {
if (newData) {
Serial.write("Received Command: ");
Serial.write(Buffer, buffer_index);
Serial.write(nl);
Serial.flush();
}
}
// return average of n reads of thermister temperature in °C
inline float readTemperature(int pin) {
float degC = 0.0;
for (int i = 0; i < n; i++) {
degC += analogRead(pin) * 0.322265625 - 50.0; // use for 3.3v AREF
//degC += analogRead(pin) * 0.170898438 - 50.0; // use for 1.75v AREF
}
return degC / float(n);
}
void parseCommand(void) {
if (newData) {
String read_ = String(Buffer);
// separate command from associated data
int idx = read_.indexOf(sp);
cmd = read_.substring(0, idx);
cmd.trim();
cmd.toUpperCase();
// extract data. toFloat() returns 0 on error
String data = read_.substring(idx + 1);
data.trim();
val = data.toFloat();
// reset parameter for next command
memset(Buffer, 0, sizeof(Buffer));
buffer_index = 0;
newData = false;
}
}
void sendResponse(String msg) {
Serial.println(msg);
}
void sendFloatResponse(float val) {
Serial.println(String(val, 3));
}
void sendBinaryResponse(float val) {
byte *b = (byte*)&val;
Serial.write(b, 4);
}
void dispatchCommand(void) {
if (cmd == "A") {
setHeater1(0);
setHeater2(0);
sendResponse("Start");
}
else if (cmd == "LED") {
ledTimeout = millis() + 10000;
LED = max(0, min(100, val));
sendResponse(String(LED));
}
else if (cmd == "P1") {
P1 = max(0, min(255, val));
sendResponse(String(P1));
}
else if (cmd == "P2") {
P2 = max(0, min(255, val));
sendResponse(String(P2));
}
else if (cmd == "Q1") {
setHeater1(val);
sendFloatResponse(Q1);
}
else if (cmd == "Q1B") {
setHeater1(val);
sendBinaryResponse(Q1);
}
else if (cmd == "Q2") {
setHeater2(val);
sendFloatResponse(Q2);
}
else if (cmd == "Q2B") {
setHeater1(val);
sendBinaryResponse(Q2);
}
else if (cmd == "R1") {
sendFloatResponse(Q1);
}
else if (cmd == "R2") {
sendFloatResponse(Q2);
}
else if (cmd == "SCAN") {
sendFloatResponse(readTemperature(pinT1));
sendFloatResponse(readTemperature(pinT2));
sendFloatResponse(Q1);
sendFloatResponse(Q2);
}
else if (cmd == "T1") {
sendFloatResponse(readTemperature(pinT1));
}
else if (cmd == "T1B") {
sendBinaryResponse(readTemperature(pinT1));
}
else if (cmd == "T2") {
sendFloatResponse(readTemperature(pinT2));
}
else if (cmd == "T2B") {
sendBinaryResponse(readTemperature(pinT2));
}
else if (cmd == "VER") {
sendResponse("TCLab Firmware " + vers + " " + boardType);
}
else if (cmd == "X") {
setHeater1(0);
setHeater2(0);
sendResponse("Stop");
}
else if (cmd.length() > 0) {
setHeater1(0);
setHeater2(0);
sendResponse(cmd);
}
Serial.flush();
cmd = "";
}
void checkAlarm(void) {
if ((readTemperature(pinT1) > limT1) or (readTemperature(pinT2) > limT2)) {
alarmStatus = 1;
}
else {
alarmStatus = 0;
}
}
void updateStatus(void) {
// determine led status
ledStatus = 1;
if ((Q1 > 0) or (Q2 > 0)) {
ledStatus = 2;
}
if (alarmStatus > 0) {
ledStatus += 2;
}
// update led depending on ledStatus
if (millis() < ledTimeout) { // override led operation
analogWrite(pinLED1, LED);
}
else {
switch (ledStatus) {
case 1: // normal operation, heaters off
analogWrite(pinLED1, loLED);
break;
case 2: // normal operation, heater on
analogWrite(pinLED1, hiLED);
break;
case 3: // high temperature alarm, heater off
if ((millis() % 2000) > 1000) {
analogWrite(pinLED1, loLED);
} else {
analogWrite(pinLED1, loLED/4);
}
break;
case 4: // high temperature alarm, heater on
if ((millis() % 2000) > 1000) {
analogWrite(pinLED1, hiLED);
} else {
analogWrite(pinLED1, loLED);
}
break;
}
}
}
// set Heater 1
void setHeater1(float qval) {
Q1 = max(0., min(qval, 100.));
analogWrite(pinQ1, (Q1*P1)/100);
}
// set Heater 2
void setHeater2(float qval) {
Q2 = max(0., min(qval, 100.));
analogWrite(pinQ2, (Q2*P2)/100);
}
// arduino startup
void setup() {
analogReference(EXTERNAL);
while (!Serial) {
; // wait for serial port to connect.
}
Serial.begin(baud);
Serial.flush();
setHeater1(0);
setHeater2(0);
ledTimeout = millis() + 1000;
}
// arduino main event loop
void loop() {
readCommand();
if (DEBUG) echoCommand();
parseCommand();
dispatchCommand();
checkAlarm();
updateStatus();
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 KiB

Binary file not shown.

Binary file not shown.
Loading…
Cancel
Save