This repository contains the Arduino firmware that implements a humidistat (humidity controller) by actuating two solenoid valves. The firmware can be used on a variety of Arduino-compatible boards, but is developed for and tested on the following MCU boards:
- Arduino Uno (AVR ATmega328P)
- Teensy LC (ARM Cortex-M0+)
- Teensy 4.0 (ARM Cortex-M7)
Besides the Arduino firmware, it contains a real-time monitoring/logging tool written in Python, which communicates with the MCU over serial.
PlatformIO Core is required for building the firmware.
The firmware is written in a modular way in order to ensure compatibility with multiple MCUs, sensors, controller
types, and even UIs, while still keeping to a single shared codebase and avoiding code duplication. In order to configure the firmware, edit src/config.h
.
This file contains macros that control which modules are used, and a number of configurable constants.
This firmware contains two variants of the actual humidity controller: SingleHumidistat
and CascadeHumidistat
.
The former implements a single-loop PID controller that regulates the humidity by directly driving two solenoid valves.
In contrast, the latter implements cascade PID control: the outer humidity control loop adjusts the setpoints of two inner (flow) control loops, that in turn drive a solenoid valve each. This control scheme leads to improved stability and performance, but requires flow sensors to provide feedback to the inner controllers.
To use the single-loop control, uncomment the line that defines HUMIDISTAT_CONTROLLER_SINGLE
. To use cascade control,
uncomment the line that defines HUMIDISTAT_CONTROLLER_CASCADE
. In the latter case, Omron D6F-P0010 flow sensors must
be connected to (analog input) pins defined by PIN_F1
and PIN_F2
.
Two types of humidity sensors are supported: the DHT22/AM2302 sensors, and the Sensirion SHT85. The former uses an
ad-hoc single-wire protocol, and can be connected to any digital input pin (as defined by PIN_DHT
). The latter
communicates over I2C, and as such must be connected to the MCU's hardware I2C bus.
To use the DHT22/AM2302 sensor, uncomment the line that defines HUMIDISTAT_DHT
. For the SHT85, uncomment the line
that defines HUMIDISTAT_SHT
.
For input, two keypads are supported: the keypad integrated on the Keyestudio Ks0256 LCD1602 Expansion Shield, and the Keyestudio Ks0466 Button Module (or clones). Both are 5-button (direction + select) resistance ladders, but their button-resistance mappings differ.
To use the keypad integrated on the Keyestudio Ks0256, uncomment the line that defines HUMIDISTAT_INPUT_KS0256
.
For the Ks0466, uncomment the line that defines HUMIDISTAT_INPUT_KS0466
.
This firmware comes with two separate UIs: one for a (HD44780-style) 16x2 character display called CharDisplayUI
,
and a more elaborate UI for a (ST7920) 128x64 graphical display called GraphicalDisplayUI
.
For the GraphicalDisplayUI
, in turn two variants exist (implemented as specialisations of the templatised class):
one for the aforementioned SingleHumidistat
and CascadeHumidistat
. This makes for a grand total of three
existing UI variants. (due to its limited space, there is no UI for the CascadeHumidistat
for the 16x2 character
display)
To use the 16x2 character display, uncomment the line that defines HUMIDISTAT_UI_CHAR
. For the 128x64 graphical
display, uncomment the line that defines HUMIDISTAT_UI_GRAPH
.
❗ Because of the ATmega328P's limited memory (both flash and RAM), the
GraphicalDisplayUI
cannot be used on the Arduino Uno. By extension, since theCharDisplayUI
doesn't supportCascadeHumidistat
,CascadeHumidistat
unfortunately cannot be used on the Arduino Uno.
Besides the macros discussed above, config.h
contains a list of compile-time constants that you want to check and
possible modify. Some of these are customisable by the operator on the device itself, using the EEPROM, if the
GraphicalDisplayUI
is used.
- Serial symbol rate
- EEPROM settings
- Arduino I/O pin numbers (for sensor, buttons, LCD, solenoid valves, thermistors)
- PID/logger/sensor interval
- PID parameters:
- Low CV value (deadband)
- Gains (Kp, Ki, Kd, Kf)
- Smoothing factor of EMA filter for derivative
- Setpoint profiles
- UI/input settings
Make sure to set these parameters to their appropriate values before compilation.
With the MCU board connected over USB, compile the firmware and upload it to the MCU:
~/OpenHumidistat/ $ platformio run --target upload
On powerup, the MCU shows a splash screen followed by an info screen printing the active tuning parameters. Subsequently, the system is ready for use. An outline of the UI is shown below.
The values shown on the display are:
- Mode: 0 for manual, 1 for auto.
- PV: Process variable, i.e. the current, measured humidity in the chamber.
- SP: Setpoint, i.e. the desired humidity. This blinks if it is too far from the PV.
- CV: Control variable, representing the state of the valves from 0 to 100%.
- MOSFET/Solenoid temperatures in Celsius.
- Chamber temperature in Celsius.
It starts in manual (open-loop) mode by default. Press SELECT to switch the controller into auto mode. Press LEFT/RIGHT for coarse adjustment of the setpoint, and DOWN/UP for fine adjustment. In manual mode, the same buttons are used to adjust the control variable.
The GraphicalDisplayUI is a modal UI with three tabs: Main
, Info
, and Config
(shown in the bar at the very top of
the screen). The Main
tab is open by default. In this tab, the up
/down
buttons adjust the currently
selected variable. Long presses give faster repeat speed.
When the controller is in manual
, the control variable (CV
) is the selected variable. In auto
, the setpoint
(SP
) is the selected variable. To toggle between manual
and auto
mode, press the ⚫select
button.
To start/stop the setpoint profile, press the ➡️right
button. The setpoint profile can be selected in
the Info
tab.
To switch to the other tab, press the ⬅️left
button.
In the info tab, temperatures of the chamber and thermistors are printed. The up
/down
buttons
select the setpoint profiles.
In the config tab, a number of controller parameters can be adjusted from the defaults as configured in src/config. h
, and saved in EEPROM.
In this tab, the up
/down
buttons scroll through the list of parameters.
To edit a parameter, press ⚫select
. Now, the left
/right
buttons can be used to
select the digit to adjust with up
/down
. Press ⚫select
again to confirm.
With ➡️right
, the menu can be reached. In this menu, the current settings can be applied and saved to
EEPROM, or reset from the defaults stored in flash memory.
stateDiagram-v2
direction LR
[*] --> tab_main
state tab_main {
[*] --> manual
auto: Auto\n ↕️ adjust SP
manual: Manual\n ↕️ adjust CV
manual --> auto : ⚫
auto --> manual : ⚫
spp_stopped: Setpoint profile\n stopped
spp_running: Setpoint profile\n running
spp_stopped --> spp_running: ➡️
spp_running --> spp_stopped: ➡️
}
state tab_config {
[*] --> select_parameter
select_parameter: Select parameter\n ↕️ scroll through parameter list
edit_parameter_value: Edit parameter value\n ↔️ select digit\n ↕️ adjust digit
actions_menu: Actions menu\n ↕️ scroll through menu\n ⚫ OK
select_parameter --> edit_parameter_value: ⚫
select_parameter --> actions_menu: ➡️
actions_menu --> select_parameter: ➡️
actions_menu --> select_parameter: ⬅️
edit_parameter_value --> select_parameter: ⚫
}
state tab_info {
[*] --> select_setpoint_profile
select_setpoint_profile: Select setpoint profile\n ↕️ scroll through setpoint profile list
}
tab_main --> tab_info: ⬅️
tab_info --> tab_config: ⬅️
tab_config --> tab_main: ⬅️
The device can operate fully in a standalone manner, but it is possible to connect it to a PC over serial (USB) running a Python script for real-time monitoring and recording of data.
The serial monitor requires at least Python 3.6. It depends on Numpy and Pandas for data structures, on PySerial for communicating with the OpenHumidistat MCU, and on Matplotlib and PyQt5 for plotting.
The dependencies can be installed in a virtualenv using Pipenv:
~/OpenHumidistat/ $ pipenv install
~/OpenHumidistat/ $ pipenv shell
(OpenHumidistat) ~/OpenHumidistat/ $
If you do not have Pipenv, you can install with pip install pipenv
.
With the Arduino connected over USB, run the serial monitor:
~/OpenHumidistat/ $ pipenv shell
(OpenHumidistat) ~/OpenHumidistat/ $ utils/monitor.py
The Arduino will reset when the serial port is opened. After connection is established, a window will open in which the data is plotted in real-time.
When the serial monitor is closed (by SIGINT), it will save the data to file, in (gzipped) CSV format.
Developer documentation is available at https://openhumidistat.github.io/firmware/.
The device for which this firmware is intended, is described in the following papers:
First version, using Arduino Uno, single-loop PID controller, DHT22/AM2302 humidity sensor, and 16x2 character display:
Veldscholte, L.B., Horst, R.J. & de Beer, S.
Design, construction, and testing of an accurate low-cost humidistat for laboratory-scale applications.
Eur. Phys. J. E 44, 48 (2021).
https://doi.org/10.1140/epje/s10189-021-00062-5
Second, improved version, using Teensy LC, cascade PID controller, SHT85 humidity sensor, and 128x64 graphical display:
Veldscholte, L. B., de Beer, S.
OpenHumidistat: Humidity-controlled experiments for everyone.
HardwareX 11, e00288 (2022).
https://doi.org/10.1016/j.ohx.2022.e00288
If you are using OpenHumidistat in your research, it is much appreciated if you cite the relevant paper(s).
This project is free software licensed under the GPL. See LICENSE for details.