While running a Lua script, the T4, T7, or T7-Pro can operate without computer involvement. Basically, user-specified operations (feedback loops, logging, PID loops) can be conducted via on-board script, which was not possible in previous generations of LabJack hardware. Below is a screenshot of the Lua Scripting section in our free cross-platform program called Kipling.
Kipling's Lua scripting tab is the best way to develop embedded Lua scripts. It simplifies viewing, testing, and configuring Lua scripts. If you are new to Lua Scripting, see you may wish to see Getting Started.
To view Lua scripts without Kipling, please see our Kipling Git repository. (Our examples are also available in Kipling.)
Key Feature of Lua Scripting: USER_RAM registers
One common application of Lua Scripts is to execute tasks and export status variables to a logging program. These scripts can use USER_RAM registers to pass data from the Lua script to any other program accessing the T-Series device. LabVIEW, C#, Python, or any other supported languages can access the T-Series device and read from or write to these registers. LJLogM can be used for easy logging of data from the various sensors. Several example scripts like these can be found in the I2C Sensor Examples website section.
One prime example is the Accelerometer & Compass Module (LSM303) example in which a script saves data from the sensor to USER_RAM registers. The USER_RAM registers can then be logged by LJLogM.
Reaching the maximum size of a Lua Script using a T7 and T4 is easy to do. The majority of the scripts that we have written show that the maximum size of a script is right around 100 lines. However, the exact size is hard to determine since it ultimately depends on what variables are being defined, how long is each line of code, etc. If you start running into some intermittent errors like "not enough memory", it is time to either refactor your code or re-consider how much you are trying to do in a script. You can try minifying your code using this online Lua Minifier tool.
These examples provide a brief overview of LabJack Lua scripting functions, including a list of functions as well as everyone's first program, "Hello World".
DEVICE_NAME_DEFAULT
Reads return the current device name. Writes update the default and current device name. A reboot is necessary to update the name reported by NBNS. Up to 49 characters, cannot contain periods.
60500
STRING
R/W
DEVICE_NAME_DEFAULT
- Address: 60500
Reads return the current device name. Writes update the default and current device name. A reboot is necessary to update the name reported by NBNS. Up to 49 characters, cannot contain periods.
Data type: STRING (type index = 98)
Readable and writable
ETHERNET_IP
Read the current IP address of wired Ethernet.
49100
UINT32
R
ETHERNET_IP
- Address: 49100
Read the current IP address of wired Ethernet.
Data type: UINT32 (type index = 1)
Read-only
ETHERNET_MAC
The MAC address of the wired Ethernet module.
60020
UINT64
R
ETHERNET_MAC
- Address: 60020
The MAC address of the wired Ethernet module.
Data type: UINT64 (type index = N/A)
Read-only
HARDWARE_VERSION
The hardware version of the device.
60002
FLOAT32
R
HARDWARE_VERSION
- Address: 60002
The hardware version of the device.
Data type: FLOAT32 (type index = 3)
Read-only
FIRMWARE_VERSION
The current firmware version installed on the main processor.
60004
FLOAT32
R
FIRMWARE_VERSION
- Address: 60004
The current firmware version installed on the main processor.
These LabJack functions are very useful when scripting for T-series devices. It may be helpful to read through this script before writing a new Lua script. This contains information specific to the T-series devices, not just Lua in general.
The examples in this section provide a brief overview of different communication types for external sensors of varying type. Most sensors use digital communication, including 1-wire, SPI, I2C, and UART. A few analog sensor examples are below, although most types of analog sensors are simple enough to be handled by analog input extended features (AIN_EF) or by a program running on a computer.
The following examples outline how I2C communication can be achieved in Lua scripts.
The below examples utilize the I2C library with the functions built in to the firmware. More detail (at the ModBus register level) can be seen under the I2C Utilities, where the library is exposed as a Lua object with functions. A list of these functions with descriptions can be found here.
The T7 supports Inter-Integrated Circuit (I²C or I2C) communication as the master only. I²C is a synchronous serial protocol typically used to communicate with chips that support I2C as slave devices. More information on I2C can be found here (Wikipedia).
It is recommended to use the EIO or CIO lines for I2C communication on the T7 rather than the FIO lines. For more information on using the T7 with I2C devices, see the T7 Datasheet.
Many sensors can be on the same I2C bus, with very minimal circuitry for each additional I2C device. A total of 7 I2C devices are shown connected to the T7 below, and can all successfully connect and communicate with the T7.
These Lua scripts use the USER_RAM registers to pass data from the Lua script to any other program accessing the T-Series device. LabVIEW, C#, Python, or any other supported languages can access the T-Series device and read from or write to these registers. LJLogM, a LabJack application can be used for easy logging of data from the various sensors.
Double check to make sure pull-up resistors are installed. A general rule for selecting the correct size pull-up resistors is to start with 4.7kΩ and adjust down to 1kΩ as necessary. If necessary, an oscilloscope should be used to ensure proper digital signals are present on the SDA and SCL lines.
Double check to make sure the correct I/O lines are being used. It is preferred to do I2C communication on EIO/CIO/MIO lines instead of the FIO lines due to the larger series resistance (ESD protection) implemented on the FIO lines.
Use an oscilloscope to verify the SDA and SCL lines are square waves and not weird arch signals (see "I2C_SPEED_THROTTLE" or use EIO/CIO/MIO lines).
Use a logic analyzer (some oscilloscopes have this functionality) to verify the correct slave address is being used. See this EEVblog post on budget-friendly options. It is common to not take into account 7-bit vs 8-bit slave addresses or properly understand how LabJack handles the defined slave address and the read/write bits defined by the I2C protocol to perform read and write requests.
Make sure your sensor is being properly powered. The VS lines of LJ devices are ~5V and the I/O lines are 3.3V. Sometimes this is a problem. Consider buying a LJTick-LVDigitalIO or powering the sensor with an I/O line or DAC channel.
Q: I've tried everything, still no I2C Ack Bits...
Try slowing down the I2C bus using the "I2C_SPEED_THROTTLE" register/option. Reasons:
Not all I2C sensors can communicate at the full speed of the LabJack. Check the I2C sensor datasheet.
The digital signals could be getting corrupted due to the series resistors of the I/O lines on the LabJack.
Consider finding a way to verify that your sensor is still functioning correctly using an Arduino and that it isn't broken.
Try to establish communications with an LJTick-DAC to ensure the DIO are operating properly and that you are configuring I2C properly.
Q: Why is my device not being found by the I2C.search function?
See information on I2C ACK bits above.
Q: What are I2C Read and Write functions or procedures?
There are a few really good resources for learning about the general flow of I2C communication.
Q: Why am I getting a I2C_BUS_BUSY (LJM Error code 2720) error?
See information on I2C ACK Bits above. Try different pull-up resistor sizes.
Differential Pressure Sensor (SDP611)
This Lua Script is an example of how to communicate with an SDP611 differential pressure sensor from Sensirion (datasheet link). Before running this example, connect the SCL line to EIO4 and the SDA line to EIO5.
Note: The default I2C configurations don't work for this sensor. Special configurations are required to account for the "Hold Master" part of the I2C packet.
This example script collects temperature data from the MLX90614 infrared temperature sensor available through Adafruit, SparkFun, Keyestudio, or Pololu.
The data obtained from the non-contact temperature sensor is published to the registers:
USER_RAM0_F32 (Ambient temperature)
USER_RAM1_F32 (Object Temperature)
These registers can accessed by any programs reading data from a T-Series device collecting this data. This enables any logging or SCADA application to easily collect data from the MLX90614 temperature sensor without any additional complexities.
When getting started with this sensor, the datasheet for this sensor is important to read. There are multiple online tutorials through SparkFun, Adafruit, and more that can serve as supplementary documents. There is also a legacy app-note worth reading Melexis MLX90614 IR Temperature Sensor - I2C (App Note). This sensor has multiple features that allow its slave address to be reprogrammed, enabling multiple IR sensors to exist on the same I2C bus. It can also be enabled for PWM output (not utilized by this application).
Schematic & Hook-up
Below is a picture of the MLX90614 IR temperature sensor connected to a LabJack with 1.8kΩ resistors installed on a breadboard.
Below is a schematic of the MLX90614 IR Temperature sensor connected to an I2C master MCU. Again, this example used 1.8kΩ resistors.
In this example, the MLX90614 IR Temperature sensor is connected to EIO6 and EIO7. A 3.3V supply was not needed to properly control this sensor. The VS could be 5V while the I/O lines were communicating with 3.3V logic.
Working Example with LJLogM
After configuring the below example script using Kipling, data can be collected using LJLogM.
This Lua script is useful as an example of how to combine I2C communication between many slave devices. This example utilizes a collection of I2C sensors, which are all available on the Adafruit 10-Degrees of Freedom Inertial Measurement Unit (10-DOF IMU, available here: https://www.adafruit.com/product/1604)
This example uses the following I2C Sensors:
L3GD20H Triple-Axis Gyro
LSM303 Triple-axis Accelerometer**
LSM303 Triple-axis Magnetometer**
*The BMP180 Barometric Pressure Sensor was not implemented in this example because of Lua script limitations. See the BMP180 Lua script for more information.
**Although the LSM303 devices are in the same package, they behave as two separate devices. See the LSM303 Accelerometer & Magnetometer Lua Script for more information.
Each of the 3 sensors must be initialized over I2C (to configure parameters such as range, data rate, and low/high power mode.
To switch between devices, the I2C bus is configured for one address, and MB.W(5104, 0, yourNewI2CAddress) is used to switch between slave devices. Reconfiguring the bus with I2C.config() would work, but takes unnecessarily long.
For more information on each I2C sensor, visit their specific lua script example.
Image 1 - L3GD20H and LSM303 breakout board.
The 10 DOF board requires very few components to run, a 3.3V supply is provided by the LJTick-LVDigitalIO.
Image 2 - T7-Pro connected to Adafruit 10-DOF.
The accelerometer can be tested by rotating it at angles to the earth, where +1.0g and -1.0g can be measured. Below is a graph of the accelerometer data (X is white, Y is red, Z is green) as the module is rotated.
This script configures the accelerometer inside the LSM303, as well as the magnetometer. These, while in the same package, behave as separate devices with different I2C addresses. The accelerometer can measure acceleration up to ±16g in each axis, and the magnetometer can measure up to 8.1 gauss in each axis. The main purpose of this unit is for a tilt-compensated compass, although it can be used for a variety of functions, depending on the application. The LSM303 on a breakout board is available here: https://www.adafruit.com/product/1120
The data obtained from the accelerometer and magnetometer is published to USER_RAM registers, which can be accessed by any other programs connected to the T-Series device. This allows a program to be doing one task while the device simultaneously obtains the accelerometer and/or magnetometer data.
The other functionalities of this device, like configurable interrupts, fall detection, and tap detection can be configured just as the other options are configured, although these specialized functions are outside the scope of this example.
Below is the LSM303, as a part of the Adafruit 10DOF board.
The 10 DOF board requires very few components to run, a 3.3V supply is provided by the LJTick-LVDigitalIO.
The accelerometer can be tested by rotating it at angles to the earth, where +1.0g and -1.0g can be measured. Below is a graph of the accelerometer data (X is white, Y is red, Z is green) as the module is rotated.
This script configures the magnetometer inside the LSM303, which behaves as a separate device from the accelerometer that is part of the same unit. The magnetometer can measure acceleration up to ±8.1 gauss in each axis. The main purpose of this unit is for a tilt-compensated compass, although it can be used for a variety of functions, such as free fall detection or tap detection. The LSM303 on a breakout board is available here: https://www.adafruit.com/product/1120
The data obtained from the magnetometer is published to USER_RAM registers, which can be accessed by any other programs connected to the T-Series device. This allows a program to be doing one task while the LabJack device simultaneously obtains the magnetometer data.
The datasheet is extremely useful for determining the setting on the device, such as low-power mode and range (±1.3, ±1.9, ±2.5, ±4.0, ±4.7, ±5.6, or ±8.1 gauss)
This script configures the accelerometer inside the LSM303, which behaves as a separate device from the magnetometer. The accelerometer can measure acceleration up to ±16g in each axis. The main purpose of this unit is for a tilt-compensated compass, although it can be used for a variety of functions, such as free fall detection or tap detection. The LSM303 on a breakout board is available here: https://www.adafruit.com/product/1120
The data obtained from the accelerometer is published to USER_RAM registers, which can be accessed by any other programs connected to the T-Series device. This allows a program to be doing one task while the device simultaneously obtains the accelerometer data.
The datasheet is extremely useful for determining the setting on the device, such as low-power mode and range ( ±2g, ±4g, ±8g, or ±16g)
The other functionalities of this device, like configurable interrupts, fall detection, and tap detection can be configured just as the range is configured, although these specialized functions are outside the scope of this example.
Below is the LSM303, as a part of the Adafruit 10DOF board.
The 10 DOF board requires very few components to run, a 3.3V supply is provided by the LJTick-LVDigitalIO.
The accelerometer can be tested by rotating it at angles to the earth, where +1.0g and -1.0g can be measured. Below is a graph of the accelerometer data (X is white, Y is red, Z is green) as the module is rotated.
This script measures acceleration using the widely available ADXL345 Accelerometer, which can measure acceleration up to 16g on 3 axes. The accelerometer on a breakout board is available here: https://www.sparkfun.com/products/9836
The data obtained from the accelerometer is published to USER_RAM registers, which can be accessed by any other programs connected to the T-Series device. This allows a program to be doing one task while the device simultaneously obtains the accelerometer data.
The datasheet is extremely useful for determining the setting on the device, such as low-power mode and range (2g, 4g, 8g, or 16g)
The other functionalities of this device, like configurable interrupts, fall detection, and tap detection can be configured just as the range is configured, although these specialized functions are outside the scope of this example.
In the above images, an inexpensive LJTick-LVDigitalIO was used to source the 3.3V needed for the ADXL345. A CB15 was used to expose the EIO4 and EIO5 connections.
Using a python script to read and write to the USER_RAM registers, it was possible to make a self-leveling platform using the ADXL345 and a servo motor.
This script uses the TCS34725 color sensor to determine the color of an object. The breakout board from Adafruit (https://www.adafruit.com/product/1334) has a built-in white LED to illuminate the object. This LED can be controlled by connecting it to a digital pin on the T-series devices. In the below example, FIO6 is used (although the LED pin is not connected in the images)
Information on how to use the values from the sensor can be found on the datasheet. In the example below, color (Simply "Red", "Green", or "Blue") is determined by the most intense color. Specific calculations can be created by the user for specific applications, such as detecting a hue value or the reflectivity of the object. A good understanding of the device's datasheet is important for modifying the script.
The data obtained from the gyroscope is published to USER_RAM registers, which can be accessed by any other programs connected to the T-Series device. This allows a program to be doing one task while the device simultaneously obtains the gyroscope data.
The datasheet is extremely useful for determining the setting on the device, such as low-power mode and range (±245/±500/±2000 dps)
The other functionalities of this device, like configurable interrupts, sleep mode, and the built-in temperature sensor can be configured just as the range is configured, although these specialized functions are outside the scope of this example.
Below is the gyro as a part of the Adafruit 10 DOF board.
The Gyro is connected to EIO4 and EI5 with pullup resistors. Here, it is using the LJTick-LVDigitalIO to supply the 3.3V necessary.
This script measures rotational speed (degrees per second) using the PS-ITG-3200 Gyroscope, which can measure up to 2000 degrees/sec on 3 axes. The device on a breakout board is available here: https://www.sparkfun.com/products/11977
The data obtained from the gyro is published to USER_RAM registers, which can be accessed by any other programs connected to the T-Series device. This allows a program to be doing one task while the device simultaneously obtains the gyro data.
The datasheet is helpful for identifying how to initialize the device and how to read data from the gyro.
In the above images, an inexpensive LJTick-LVDigitalIO was used to source the 3.3V needed for the ADXL345. A CB15 was used to expose the EIO4 and EIO5 connections.
The other functionalities of this device, like configurable interrupts, filtering, and other functions are outside the scope of this example, but can easily be configured in the same way the other device settings are initialized.
The script then reads the distance value from the sensor and reports it to a USER_RAM register, accessible in many other programs, such as LabVIEW, Python, C#, or the LabJack logging software, LJLogM.
The range finder sensor is easily connected using the EB37 and CB15 Accessories.
This script measures the distance to a large, flat object up to 255 inches away (21 feet) using the I2C bus. The SRF02 Sensor uses ultrasonic pings to bounce off of large objects and detect the distance.
A register on the SRF02 must be written with the value 0x50 to initiate the ping. After a short delay, the corresponding registers can be read to obtain distance in inches or centimeters. A variety of documentation can be found online regarding the SRF02.
The data obtained from the sensor is published to USER_RAM registers, which can be accessed by any other programs connected to the T-Series device. This allows a program to be doing one task while the device simultaneously obtains the range sensor data.
In the image above, a battery pack is used to supply power to the T7-Pro, and data is acquired over WiFi, allowing the assembly to be moved anywhere within a building while operating.
This script measures temperature and barometric pressure using the BMP180 sensor. The calculations for the BMP180 to take the data and calibration constants and determine the atmospheric pressure is too large for Lua, and is completed through a python script running on a PC instead.
Below is the BMP180 as a part of the Adafruit 10DOF board. A BMP180, with the appropriate passive components, will function identically to the BMP180 on the 10DOF board.
This script operates an I/O expander over the I2C Bus. The I/O expander- the SX1509- has 16 channels, which can be configured for digital input or output (including PWM and specialized LED driver functions) and can be used to read a keypad.
The script below only uses the basic digital input and output functions of this device. This script can be modified to use other functionalities, such as the PWM driver or keypad engine.
USER_RAM registers are read by the script to write values to the digital output lines, and a separate set of USER_RAM register is written to by the script to display the digital input states.
A good understanding of the datasheet and device's functionality is important for understanding and modifying this example.
Before making the decision to use this device, keep in mind that the T7 has 23 DIO lines available.
The EB37 allows for easy prototyping of the entire circuit. The EB37 features a 3.3V regulator, which is being used to supply power to the digital I/O expander. The CB15 provides connection to the EIO lines.
A python script was used to change the USER_RAM registers to sequence through all of the digital output pins, and then write them all high at once.
The following examples push the limits of T-Series devices and report maximum frequencies. These examples use different loop structures than most other examples.
You should usually throttle your code execution using the functions:
The following scripts are more advanced in nature than the other examples.
Moving Average
Lua Scripting can be used to implement moving averaging algorithms which allow Modbus polling applications to easily oversample analog inputs and achieve the benefits of higher accuracy analog inputs on low cost devices. This is especially true when the Modbus polling applications are only requesting data once per second. For customer convenience, we have three examples that perform these calculations.
Moving Average Compute After Sampling
This script reads analog inputs and computes the moving average after each sampling interval. This script is particularly useful for Modbus polling applications that need to be sure that each "moving average" value that gets read is the most up to date value. The script can be customized by editing the constants:
local sampleIntervalHZ = 10 -- Sampling interval in HZ
local numSamplesToAverage = 100 -- Number of samples to cached & average
local channels = {0, 2} -- Which analog inputs/registers to read & average
To assist with determining maximum sampling rates and buffer sizes, digital I/O lines FIO4-5 on T4s and FIO0-1 on the T7 are configured to output waveforms that can be read with an oscilloscope or logic analyzer. As a really low-cost solution, LEDs can be installed and looked at to see how bright they are and used to determine how much idle time the script has.
This script reads analog inputs and computes the average value of each read channel on a given interval. This is useful for situations where analog inputs want to be read at high data rates. Keep in mind that while a script is computing the average value analog input values aren't being read. In time-critical applications where this is important to characterize and understand, I/O lines can be toggled and monitored with an oscilloscope to determine if the script is reading data fast enough and with low enough jitter.
This script can be customized by editing the sampling interval, number of samples to average, user-ram update rate, and channel register constants.
This script reads analog inputs and computes the average value of each read channel on a given interval. This is useful for situations where analog inputs want to be read at high data rates. Keep in mind that while a script is computing the average value analog input values aren't being read. In time-critical applications where this is important to characterize and understand, I/O lines can be toggled and monitored with an oscilloscope to determine if the script is reading data fast enough and with low enough jitter.
This script can be customized by editing the sampling interval, number of samples to average, user-ram update rate, and channel register constants.
Warning: This script calculates the moving average by maintaining a "sum" which is (in memory) a float32 data type. While the value will remain close to the true value, the precision may slowly drift.
Stepper motors can be controlled with a LabJack by loading one of the following .lua scripts and executing the python script or our windows only example application written in LabVIEW. For more detail see the Stepper Motor Controller app-note.
Full Step Unipolar Stepper Motor Control
This script is meant to be loaded and controlled as part of a larger stepper motor controller application. See the Stepper Motor Controller App-Note for more details.
This script is meant to be loaded and controlled as part of a larger stepper motor controller application. See the Stepper Motor Controller App-Note for more details.
This python script loads and executes a .lua script and then sends data to control the position of the motor. More details about this python script and controlling stepper motors with LabJack T-Series devices can be found in the Stepper Motor Controller app-note.
The examples in this section demonstrate how to make counters, with digital inputs, analog inputs, and debounce. Individual counters can be set to increment on either rising or falling edges.
Lua Scripts can be useful for configuring analog inputs on a device both to read them back and to save values as power-up defaults so that devices can be integrated into 3rd party SCADA systems.