This repository contains the code to configure oscilloscopes, signal generators, DC Power-supplies and other measurement
devices.
It provides following functionality:
- Establishing a network connection and identifying the different types of devices
- Execution of VISA commands on the devices. E.g. setting the voltage on a DC power-supply, Setting voltage limits on
SMUs or to gather the current data of an oscilloscope
- CSV export function to directly store the output of measure devices in an *.csv file.
- Environment to set up test cases, configured by an XML file.
- Platform independent implementation (tested on Windows, MAC OS and Ubuntu)
OS | Status |
---|---|
Windows Latest | |
Mac OS Latest | |
Ubuntu Latest |
See https://florianfrank.github.io/instrument_control_lib/index.html for an overview of all available operations and further documentation. This documentation is built automatically, so it is always up to date.
git clone git@github.com:FlorianFrank/instrument_control_lib.git
Adjust the configuration files according to your needs.
option(INSTRUMENT_LIB_BUILD_STATIC "Build instrument lib as static library" ON)
# Definitions for the platform independent abstraction layer.
option(PIL_COMMUNICATION "Enable PIL Sockets" ON)
option(PIL_THREADING "Enable PIL Threads" ON)
option(PIL_LOGGING "Enable Logging support" ON)
option(PIL_SHARED "BUILD PIL as shared library" OFF)
option(PIL_STATIC "BUILD PIL as static library" ON)
option(PIL_CXX "Enable PIL C++ support" ON)
# PugiXML options
option(BUILD_SHARED_LIBS "Build pugiXML as shared lib" OFF)
set(PUGI_XML_VERSION 1.12)
On Linux and MAC OS run:
./build.sh
On Windows run:
.\build.bat
You can find the library in the build folder.
out
├── include Here you can find the device and include fines for the project
├── ĺib Here you can find the libraries to link to your project.
├── bin In this folder you can find sample test programs, like a command line interface.
├── doc This folder contains the doxygen documentation.
Go to:
Instrument Control Packages and download the preferred
version.
Execute:
dpkg -i instrument_control_lib.deb
The files are copied into the /usr/bin, /usr/lib/, and /usr/include folders and can be linked and included in any program.
Run the graphical installer.
Run the graphical installer.
See the examples directory for samples on how to use this lib with C++ and with Python.
#include "kst33500.h" // include right device header file
int main() {
// provide a IP address, some devices may need an extra port parameter
KST33500 k("xx.xx.xx.xx", <timeout>);
k.Connect();
}
In this lab, we use sockets to send SCPI commands to devices in order
control them remotely.
Check the documents in Docs for SCPI commands.
Basically, you can run any commands using Exec commands. For saving time, we wrapped some frequently used commands. But we cannot wrap all the commands.
Here is an instruction for wrapping a command. Let's say you want to wrap a command of Keysight waveform generator:
FUNCtion <function>
which sets a waveform.
Go to kst33500.h file and add a function signature called "function".
int function(string fun);
Go to kst33500.cpp file and add the implementation of this function. What you need to do is making an SCPI command and invoke the Exec function.
int KST33500::function(string fun) {
string msg = "FUNCtion " + fun;
Exec(msg);
return 0;
}
That's it. After that, you can use it like this:
k.function("SIN");
-
Easy installation with pip.
Execute
pip install .
in the root directory to install the instrument control lib for the current python installation. You can now just import py_instrument_control_lib and use it just like the C++ lib. With the pip installer the lib now supports autocompletion and type hints. -
Open the python console
- Make sure you installed the lib using pip
- Open the library as module
- Create a SMU object with an IP and an timeout for the socket
- Connect to the SMU
- You can check the error code which should be ERROR_CODE.NO_ERROR
- All defined error codes are listed below
$ python3
>>> from py_instrument_control_lib import *
>>> smu = KEI2600("192.168.1.10", 2000, SEND_METHOD.DIRECT_SEND)
>>> error_code = smu.connect()
>>> print(error_code)
ERROR_CODE.NO_ERROR
>>> device_identifier = smu.getDeviceIdentifier()
>>> print(device_identifier)
Keithley Instruments Inc*, Model 2636B, 4031
>>> error_code = smu.setLevel(SMU_UNIT.VOLTAGE, SMU_CHANNEL.CHANNEL_A, 3.3, False)
>>> if error_code != ERROR_CODE.NO_ERROR:
pass # stop execution or do some error handling
>>> error_code = smu.setLimit(SMU_UNIT.VOLTAGE, SMU_CHANNEL.CHANNEL_A, 5.0, False)
>>> # error handling
>>> error_code = smu.turnOn(SMU_CHANNEL.CHANNEL_A, False)
>>> # error handling
>>> measure_value = smu.measure(SMU_UNIT.CURRENT, SMU_CHANNEL.CHANNEL_B, False)
>>> print(measure_value)
3.04
>>> smu.disconnect()
This list gives an overview of the smu functions and how to call them.
# Establish the connection to the device
error_code = smu.connect()
error_code = smu.disconnect()
error_code = smu.turnOn(SMU_CHANNEL.CHANNEL_A, False)
error_code = smu.turnOff(SMU_CHANNEL.CHANNEL_A, False)
value = smu.measure(SMU_UNIT.CURRENT, SMU_CHANNEL.CHANNEL_A, False)
value = smu.measure(SMU_UNIT.VOLTAGE, SMU_CHANNEL.CHANNEL_A, False)
value = smu.measure(SMU_UNIT.RESISTANCE, SMU_CHANNEL.CHANNEL_A, False)
value = smu.measure(SMU_UNIT.POWER, SMU_CHANNEL.CHANNEL_A, False)
error_code = smu.setLevel(SMU_UNIT.VOLTAGE, SMU_CHANNEL.CHANNEL_A, 3.3, False)
error_code = smu.setLevel(SMU_UNIT.CURRENT, SMU_CHANNEL.CHANNEL_A, 0.1, False)
error_code = smu.setLimit(SMU_UNIT.VOLTAGE, SMU_CHANNEL.CHANNEL_A, 3.3, False)
error_code = smu.setLimit(SMU_UNIT.CURRENT, SMU_CHANNEL.CHANNEL_A, 0.1, False)
error_code = smu.enableMeasureAutoRange(SMU_UNIT.VOLTAGE, SMU_CHANNEL.CHANNEL_A, False)
error_code = smu.enableMeasureAutoRange(SMU_UNIT.CURRENT, SMU_CHANNEL.CHANNEL_A, False)
error_code = smu.disableMeasureAutoRange(SMU_UNIT.VOLTAGE, SMU_CHANNEL.CHANNEL_A, False)
error_code = smu.disableMeasureAutoRange(SMU_UNIT.CURRENT, SMU_CHANNEL.CHANNEL_A, False)
error_code = smu.enableSourceAutoRange(SMU_UNIT.VOLTAGE, SMU_CHANNEL.CHANNEL_A, False)
error_code = smu.enableSourceeAutoRange(SMU_UNIT.CURRENT, SMU_CHANNEL.CHANNEL_A, False)
error_code = smu.disableSourceAutoRange(SMU_UNIT.VOLTAGE, SMU_CHANNEL.CHANNEL_A, False)
error_code = smu.disableSourceAutoRange(SMU_UNIT.CURRENT, SMU_CHANNEL.CHANNEL_A, False)
smu.setSenseMode(SMU_CHANNEL.CHANNEL_A, SMU_SENSE.LOCAL, False)
error_code = smu.setSourceRange(SMU_UNIT.VOLTAGE, SMU_CHANNEL.CHANNEL_A, 3.0, False)
device_description = smu.getDeviceIdentifier()
There is a function which transforms the error codes into Strings. Some error codes are not used in the library because these are derived from the abstraction library. This function will be implemented in python soon!
# No error occurred
NO_ERROR
# Invalid arguments passed to a function, e.g. passing a nullptr.
PIL_INVALID_ARGUMENT
# An error occured and an errno error code was set.
# Internal error message can be requested by the error handle
ERRNO
# Error when performing an operation on a closed interface.
INTERFACE_CLOSED
# Error when baudrate cannot be set. E.g. when the approximation function has a higher deviation then 2 %.
INVALID_BAUDRATE
# Error insufficient resources.
INSUFFICIENT_RESOURCES
# Error, insufficient permissions to perform a certain operation.
INSUFFICIENT_PERMISSIONS
# Error, when deadlock is detected in a multithreaded application.
DEADLOCK_DETECTED
# Error while joining a thread.
THREAD_NOT_JOINABLE
# Error performing an operation on on a not initialized thread.
THREAD_NOT_FOUND
# Error entire file could not be written.
ONLY_PARTIALLY_READ_WRITTEN
# Error no such file or directory.
NO_SUCH_FILE
# Invalid error code.
UNKNOWN_ERROR
# Error while parsing an XML file.
XML_PARSING_ERROR