Notice: This page contains information for the legacy Phidget21 Library. Phidget21 is out of support. Bugfixes may be considered on a case by case basis. Phidget21 does not support VINT Phidgets, or new USB Phidgets released after 2020. We maintain a selection of legacy devices for sale that are supported in Phidget21. We recommend that new projects be developed against the Phidget22 Library.
|
Data Logging With a Thermocouple: Difference between revisions
(→Code) |
|||
Line 282: | Line 282: | ||
<div class="source"> | <div class="source"> | ||
<syntaxhighlight line start="1" lang=cpp> | |||
#include <stdio.h> | |||
#include <stdlib.h> | |||
#include <time.h> | |||
#include <sys/time.h> | |||
#include <phidget21.h> | |||
// This struct gets passed through the "usrptr" part of the Phidgets API | |||
struct userStruct { | |||
struct timespec start; | |||
FILE *outputFile; | |||
}; | |||
// Create a listener function for changes in thermocouple temperature | |||
int TemperatureDataHandler(CPhidgetTemperatureSensorHandle device, | |||
void *userptr, int index, double data) | |||
{ | |||
double ambientTemperature; | |||
struct timespec now; | |||
double timeDifference; | |||
clock_gettime(CLOCK_REALTIME, &now); | |||
// Extract the passed user data structure, and the file pointer within it | |||
struct userStruct *passedData = (struct userStruct *) userptr; | |||
FILE *file = passedData->outputFile; | |||
// Get the board temperature | |||
CPhidgetTemperatureSensor_getAmbientTemperature(device, &ambientTemperature); | |||
// Print dot to the screen to indicate one more data point recorded | |||
printf("."); | |||
fflush(stdout); | |||
// Sums the seconds plus nanoseconds | |||
// Translates to seconds by using 10^9 nanoseconds per second | |||
timeDifference = ((now.tv_sec - passedData->start.tv_sec) + | |||
(float) (now.tv_nsec - passedData->start.tv_nsec) / 1000000000.0); | |||
fprintf(file, "%6f, %6f, %6f\n", timeDifference, data, ambientTemperature); | |||
fflush(file); | |||
return 0; | |||
} | |||
int main(int argc, char* argv[]) { | |||
int result; | |||
char character; | |||
// Obtain an intial time from which to generate timestamps | |||
struct timespec start; | |||
clock_gettime(CLOCK_REALTIME, &start); | |||
// Clear and open the file for writing | |||
FILE *file = fopen("temperature_data.csv","w"); | |||
struct userStruct userData; | |||
userData.start = start; | |||
userData.outputFile = file; | |||
// Print the header at the top of the file first thing | |||
fprintf(file, "Time,Thermocouple-Temperature,Ambient-Board-Temperature\n"); | |||
// Create the Phidget software object, hook in the event function, and open the object | |||
CPhidgetTemperatureSensorHandle device = 0; | |||
CPhidgetTemperatureSensor_create(&device); | |||
CPhidgetTemperatureSensor_set_OnTemperatureChange_Handler(device, | |||
TemperatureDataHandler, (void *) &userData); | |||
CPhidget_open((CPhidgetHandle)device, -1); | |||
result = CPhidget_waitForAttachment((CPhidgetHandle)device, 10000); | |||
if (result) { | |||
printf("No Device!\n"); | |||
return 0; | |||
} | |||
// Set the thermocouple type and trigger (0 = record all data) | |||
CPhidgetTemperatureSensor_setTemperatureChangeTrigger(device, 0, 0); | |||
CPhidgetTemperatureSensor_setThermocoupleType(device, 0, | |||
PHIDGET_TEMPERATURE_SENSOR_K_TYPE); | |||
printf("Press Enter to end\n"); | |||
getchar(); | |||
CPhidget_close((CPhidgetHandle)device); | |||
CPhidget_delete((CPhidgetHandle)device); | |||
fclose(file); | |||
return 0; | |||
} | |||
</syntaxhighlight> | |||
</div> | </div> | ||
Some highlights: | |||
* Line 16 and 26: To create timestamps for the data being recorded, we use {{Code|time()}} to accurately obtain the elapsed time. | |||
* Lines 19: We start with a fresh, empty file with the same name each time, overwriting previous contents. | |||
* Line 49: We used a K-type thermocouple. '''You need to change this line to your thermocouple type'''. | |||
* Line 51: We set the sensitivity (trigger) to 0, to record all data. Setting a value above 0 will only record changes greater than or equal to that value. | |||
Revision as of 18:26, 12 April 2012
The project described here is a data recording program for the Phidget Temperature Sensors. We play with the program and record data to learn things about our environment. The emphasis in this project is on passing data and writing to files in different languages, to also learn about data logging in general.
Practical concepts covered are (click on links to see other projects on that topic):
|
As with any of our described projects, Phidgets takes care of the electrical component design. Here, we also provide some simple code so you can play around with your Temperature Sensor and thermocouple, and save the data to plot later.
Time: | About two hours for the basics, three hours for looking at and analysing the data |
Special Needed Tools: | Something hot (tea, your skin), or something cold (ice, etc) |
Materials and Phidgets: | A Phidget Temperature Sensor (1048 or 1051), a Thermocouple, a USB cord, and your computer |
Also:
- You should have already worked through our Phidget Temperature Sensor Getting Started Guide for your Temperature Sensor - this will show you how to get the the Phidget Libraries installed for your operating system.
- Your computer should have at least one of:
- A version of Python 2.6 or later, set up with the Python Phidget Libraries
- A version of Java, set up with the Java Phidget Libraries
- If you are using Linux (or the Phidget SBC), you can also use the gcc C compiler
- Set up the Phidget C libraries on Linux
- Set up gcc for development on the Phidget SBC
- If you would like to follow along with the graphing examples, you can install the R Statistical package, which is free and available for Windows, Mac, and Linux.
Introduction
This application guide is all about basic data logging and analysis with Phidgets. The ability to write an automatic data logger is one of the strong advantages to Phidgets - you do not have to take visual readings of a thermometer (or other sensor) and record the readings in a log book manually, rather, you can simply log directly to a computer.
Thermocouples provide a way to inexpensively measure the temperature of a material through physical contact. Although we use thermocouples and a Phidget Temperature Sensor (1048 or 1051) as our Phidget to log data from, basic data logging will be similar for many other Phidgets.
Phidgets
To use the code in this Guide, you will need to have a Phidget Temperature sensor and a thermocouple.
Some example ways to set this up are:
Example Setup | Strengths |
---|---|
Basic thermocouple setup | |
Ability to measure multiple points | |
Wide temperature range thermocouple |
Of course, these are only examples - any thermocouple with either Temperature Sensor Phidget board will work.
We will log data from thermocouple port 0. On a one-input board, this is the only thermocouple input; on a four-input board, make sure you have a thermocouple plugged in to port 0:
Then:
- Make sure you have followed the Getting Started guide for your Phidget
- Make sure you have the programming language libraries that you want installed
- Plug the USB in to your computer
- Continue on to the next section and start writing code!
Code
For all platforms, we wrote code in Java and in Python. The C/C++ language has no method of accurate time stamping in a platform-independent way. The C/C++ code here was written for a POSIX (Linux and Phidget Single Board Computer) system, but can be easily adapted for Windows.
Java Code and Discussion
The data logger Java source code we used is:
import com.phidgets.*;
import com.phidgets.event.*;
import java.io.*;
public class DataLogger {
public static final void main(String args[]) throws Exception {
// Clear and open the csv file for writing, and write the header
final FileOutputStream outFile = new FileOutputStream("temperature_data_java.csv");
String header = "Time,Thermocouple-Temperature,Ambient-Board-Temperature\n";
outFile.write(header.getBytes(), 0, header.length());
outFile.flush();
// Get a start time from which we can generate timestamps later
final long start = System.nanoTime();
// Create the Phidget software object
TemperatureSensorPhidget device;
device = new TemperatureSensorPhidget();
// Attach a listener function to changes in thermocouple temperature
TemperatureChangeListener temperatureDataHandler;
device.addTemperatureChangeListener(new TemperatureChangeListener() {
public void temperatureChanged(TemperatureChangeEvent event) {
long now = System.nanoTime();
// The nanoTime() function gives us microseconds; we want seconds.
double timeDifference = (now - start) / 1000000000.0;
// Initialize the board temperature with some impossible number
double ambientTemperature = -99;
// Cast the event into a specific (TemperatureSensor) Phidget
// This must be done separately from calling a device function
TemperatureSensorPhidget localDevice = (TemperatureSensorPhidget)event.getSource();
// Get the board temperature
try {
ambientTemperature = localDevice.getAmbientTemperature();
} catch (PhidgetException exception) {
System.out.println(exception);
}
// Print dots to indiciate one more point recorded
System.out.print(".");
System.out.flush();
// Write the data to the text file
String output = timeDifference + "," + event.getValue() + "," + ambientTemperature + "\n";
try {
outFile.write(output.getBytes(), 0, output.length());
outFile.flush();
} catch (IOException exception) {
System.out.println(exception);
}
}
});
// Open the device and make sure it is plugged in
device.openAny();
device.waitForAttachment(10000);
// Set the thermocouple type and trigger (0 = record all data)
try {
device.setThermocoupleType(0, device.PHIDGET_TEMPERATURE_SENSOR_K_TYPE);
device.setTemperatureChangeTrigger(0, 0);
} catch (PhidgetException exception) {
System.out.println(exception);
}
System.out.println("Press Enter to end anytime...\n");
System.in.read();
outFile.close();
device.close();
device = null;
}
}
Some highlights:
- Line 16 and 27: To create timestamps for the data being recorded, we use
System.nanoTime()
to accurately obtain the elapsed time. - Lines 10-12 and 49-52: To start with a fresh, empty file each time, we use a
FileOutpuStream
which writes raw bytes and starts at offset 0. - Line 66: We used a K-type thermocouple. You need to change this line to your thermocouple type.
- Line 67: We set the sensitivity (trigger) to 0, to record all data. Setting a value above 0 will only record changes greater than or equal to that value.
Compile and Run
Java requires, due to the class name, that this code be saved in a file called DataLogger.java
. If you need help compiling and running Phidgets java code and linking phidget21.jar
, you should try the in-depth instructions on the Language - Java page.
Python Code and Discussion
The data logger Python source code we used is:
#! /usr/bin/python
from time import time
import sys
from Phidgets.PhidgetException import PhidgetErrorCodes, PhidgetException
from Phidgets.Events.Events import *
from Phidgets.Devices.TemperatureSensor import *
# Define an error catching function so we can call it on "try...except" blocks
def LocalErrorCatcher(event):
print("Phidget Exception: " + str(e.code) + " - " + str(e.details) + ", Exiting...")
exit(1)
# Obtain an initial time from which to generate timestamps
start = time()
# Clear and open the data file for writing
outfile = open("temperature_data_py.csv", "w")
# Create a listener function for changes in thermocouple temperature
def TemperatureDataHandler(e):
global start
global outfile
now = time() - start
# Get the board temperature
ambientTemp = e.device.getAmbientTemperature()
# Write the data to the text file
outfile.write(str(now) + "," + str(e.temperature) + "," + str(ambientTemp) + "\n")
# Print a dot to indicate one more point recorded
sys.stdout.write(".")
sys.stdout.flush()
# Write a header to the text file first thing
outfile.write("Time,Thermocouple-Temperature,Ambient-Board-Temperature\n")
# Create the Phidget software object, hook in the event function, and open the object
device = TemperatureSensor()
device.setOnTemperatureChangeHandler(TemperatureDataHandler)
device.openPhidget()
device.waitForAttach(10000)
# Set the thermocouple type and trigger (0 = record all data)
try:
device.setThermocoupleType(0, ThermocoupleType.PHIDGET_TEMPERATURE_SENSOR_K_TYPE)
except PhidgetException as e: LocalErrorCatcher(e)
device.setTemperatureChangeTrigger(0, 0)
print("Press Enter to end anytime...");
character = str(raw_input())
device.closePhidget()
exit(0)
Some highlights:
- Line 16 and 26: To create timestamps for the data being recorded, we use
time()
to accurately obtain the elapsed time. - Lines 19: We start with a fresh, empty file with the same name each time, overwriting previous contents.
- Line 49: We used a K-type thermocouple. You need to change this line to your thermocouple type.
- Line 51: We set the sensitivity (trigger) to 0, to record all data. Setting a value above 0 will only record changes greater than or equal to that value.
Compile and Run
To run the Python code on your system, you can save it in a file such as code.py
and then run it from a command line or terminal with:
python code.py
If this basic reminder doesn't help you run the code, you probably will want the in-depth instructions on the Language - Python page.
C Code and Discussion
If you are using Windows, please refer to the Java or Python section as the C code was written on Linux, including the Phidget Single Board Computer (SBC). The use of Phidgets in C on any operating system is the same. However, ANSI-based C does not include support for getting time on any resolution smaller than one second. So, to obtain timing for the data as it comes in, we need to use operating-system specific code. It would probably be fairly straightforward to modify this code to use a Windows method of obtaining time.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/time.h>
#include <phidget21.h>
// This struct gets passed through the "usrptr" part of the Phidgets API
struct userStruct {
struct timespec start;
FILE *outputFile;
};
// Create a listener function for changes in thermocouple temperature
int TemperatureDataHandler(CPhidgetTemperatureSensorHandle device,
void *userptr, int index, double data)
{
double ambientTemperature;
struct timespec now;
double timeDifference;
clock_gettime(CLOCK_REALTIME, &now);
// Extract the passed user data structure, and the file pointer within it
struct userStruct *passedData = (struct userStruct *) userptr;
FILE *file = passedData->outputFile;
// Get the board temperature
CPhidgetTemperatureSensor_getAmbientTemperature(device, &ambientTemperature);
// Print dot to the screen to indicate one more data point recorded
printf(".");
fflush(stdout);
// Sums the seconds plus nanoseconds
// Translates to seconds by using 10^9 nanoseconds per second
timeDifference = ((now.tv_sec - passedData->start.tv_sec) +
(float) (now.tv_nsec - passedData->start.tv_nsec) / 1000000000.0);
fprintf(file, "%6f, %6f, %6f\n", timeDifference, data, ambientTemperature);
fflush(file);
return 0;
}
int main(int argc, char* argv[]) {
int result;
char character;
// Obtain an intial time from which to generate timestamps
struct timespec start;
clock_gettime(CLOCK_REALTIME, &start);
// Clear and open the file for writing
FILE *file = fopen("temperature_data.csv","w");
struct userStruct userData;
userData.start = start;
userData.outputFile = file;
// Print the header at the top of the file first thing
fprintf(file, "Time,Thermocouple-Temperature,Ambient-Board-Temperature\n");
// Create the Phidget software object, hook in the event function, and open the object
CPhidgetTemperatureSensorHandle device = 0;
CPhidgetTemperatureSensor_create(&device);
CPhidgetTemperatureSensor_set_OnTemperatureChange_Handler(device,
TemperatureDataHandler, (void *) &userData);
CPhidget_open((CPhidgetHandle)device, -1);
result = CPhidget_waitForAttachment((CPhidgetHandle)device, 10000);
if (result) {
printf("No Device!\n");
return 0;
}
// Set the thermocouple type and trigger (0 = record all data)
CPhidgetTemperatureSensor_setTemperatureChangeTrigger(device, 0, 0);
CPhidgetTemperatureSensor_setThermocoupleType(device, 0,
PHIDGET_TEMPERATURE_SENSOR_K_TYPE);
printf("Press Enter to end\n");
getchar();
CPhidget_close((CPhidgetHandle)device);
CPhidget_delete((CPhidgetHandle)device);
fclose(file);
return 0;
}
Some highlights:
- Line 16 and 26: To create timestamps for the data being recorded, we use
time()
to accurately obtain the elapsed time. - Lines 19: We start with a fresh, empty file with the same name each time, overwriting previous contents.
- Line 49: We used a K-type thermocouple. You need to change this line to your thermocouple type.
- Line 51: We set the sensitivity (trigger) to 0, to record all data. Setting a value above 0 will only record changes greater than or equal to that value.
Compile and Run
The process to compile this code differs from the one described on the Language - C/C++ page. You will need to link in both the Phidgets library (-lphidget21) and the Real Time POSIX library (-lrt) when compiling your code. If you have saved the C code in a file code.c
, the gcc compiling command will be:
gcc code.c -lphidget21 -lrt
The Real Time library is required for the clock_gettime
function in the C code above. Then, the executing instructions are the same as those described on the C/C++ Language page.
Putting it All Together
The code above saves the data from the Temperature Sensor Phidget into a Comma Separated Value file (*.csv). It will be named based on the code snippet you use and written into the directory where you run the code:
- Java code writes to "temperature_data_java.csv"
- Python code writes to "temperature_data_py.csv"
- C code writes to "temperature_data.csv"
Try running the code on a command line or in a terminal. For example, if you are using the Python code and have saved it to a file code.py
, running it will give you something like this:
The other languages will look almost exactly the same. Each period "." indicates a data point being written to the file. After you have recorded what you want to record, press 'Enter' and the file will be finalized and the program will exit.
Most spreadsheet programs (Excel, Open Office) will automatically recognize a *.csv file as something they can open. You can use the spreadsheet program of your choice to open the *.csv file and look at the data you've recorded. Here, we use the program R to view and plot the data - it is free and available for many operating systems.
To import the data from the python program, we can start R on the command line with the command "R", and then import the temperature_data_py.csv
data file with:
temp.data = read.csv("temperature_data_py.csv")
This import will automatically carry over the headers from the text file. Unlike other languages, the dot "." in R can simply be used as part of a variable name. The "accessor" function for accessing the slots within an object is the dollar sign "$". To plot the temperature data, you simply type:
plot(temp.data$Time,temp.data$Thermocouple.Temperature)
Or we can pretty it up with axis labels, lines instead of dots, and some colour with:
plot(temp.data$Time,temp.data$Thermocouple.Temperature,type="l",ylim=c(0,70),xlab="Seconds",ylab="Degrees Celsius",col="blue")
Which gives:
This temperature variation was obtained by touching the sensor to warm materials, and this is a good test to make sure your leads are hooked up correctly. The large spike in temperature is due to the thermocouple being immersed into hot tea. But if the leads were backwards, as we did with a second recorded series of the same materials, it will look something like this:
Since hot tea is not colder than -10C, this is a good indication that the leads are reversed. However, the ambient temperature at the start of the series is possible but not unreasonable, so accidentally reversing the leads may only be discovered when objects of very different temperatures are measured.
At this point, you have successfully logged data from a Phidget to a text file which can also serve as a spreadsheet. If you want to learn more about how the data can be interpreted, and more about how to use your Temperature Sensor and thermocouple, read on. Otherwise, enjoy playing around with the sensor and logging data on your own!
Data Analysis
Extra Credit
- As mentioned above, the thermocouple is a contact temperature sensor - it works by becoming the same temperature as the material it is touching. There were a few materials