Image credit: Michael Buchhorn - https://doi.org/10.1039/D5DD00157A
HiPeristaltic is a fully open-source (hardware and software) peristaltic pump with multiple independent channels, developed in Germany at Helmholtz Institute Erlangen-Nürnberg for Renewable Energy/Forschungszentrum Jülich.
This repo is a part of our publication An open-source peristaltic pump with multiple independent channels for laboratory automation from team High-Throughput Electrocatalysis (HTE).
HiPeristaltic is built using 3D printed and off-the-shelf parts, with software based on Python for the user interface and pure C for the microcontroller firmware. The total cost for the entire system is approximately 280USD. It is accurate up to 0.2% volume and comes optimized, thread-safe and error-resistant software.
HiPeristaltic includes a SiLa2 software module for easy integration to digital laboratories and for Self Driving Laboratories (SDLs). SiLa2 also allows controlling the pump with a GUI over web browser for non-coder users. Additionally, Python API is available under /interface/ for non-SiLa integration.
The software stack is designed to be compatible with a wide range of MCUs (STM32, Arduino, Pico), stepper motor drivers (A4988, DRV8825, TMC2209, ...) and connectivity options (UART, USB, Ethernet/Wifi).
- Users who just want to get started can refer to Getting Started Quickly. This is the best option to replicate HiPeristaltic as published and with the recommended hardware.
- For experienced users, a step by step guide is given in Advanced Installation to enable customizations.
- For those familiar with MCU platforms and motor drivers, all other supported hardware combinations are listed under Hardware Options.
- For developers looking to integrate concurrent stepper motor control, a spin-off library MultiStepperLite is also published.
In this section, only the most straightforwad software setup to enable pump through SiLa2 is provided. The hardware connections are assumed to be completed as given in the publication. The hardware setup manual can be found in HiPeristaltic Hardware Zenodo. Furthermore, this tutorial assumes the user has the following:
- Raspberry Pi 4 Model B
- A microSD card with minimum 16GB capacity.
- BIGTREETECH SKR Mini E3 v3.0 board
- Another microSD card with minimum 1MB capacity.
- Raspberry Pi 4 Model B and the client (e.g., user or laboratory PC) computers being on the same network (i.e., both are connected to the same router or same Ethernet switch)
The following steps are the summarized points from the setup guide that includes more details and pictures/screenshots. The guide can be found in the HiPeristaltic Software Zenodo or directly here Software_Setup_Guide.pdf.
- Download and flash the Raspberry Pi image to the microSD card (one with 16GB+ capacity). The image is located in HiPeristaltic Zenodo page with filename
raspi_image.img. - Insert this microSD card to Raspberry Pi but don't turn it on yet.
- Download and place the firmware to the other SD Card (one with 1MB+ capacity). The firmware is located in HiPeristaltic Zenodo page with filename
FIRMWARE.bin. - Insert this microSD card to BIGTREETECH SKR Mini E3 v3.0 board, then power on and wait for 15 seconds.
- Power down and then re-start all devices.
- On your PC, Download SiLa2 Universal Client for Windows or for other OS.
- Make sure Java 8 is installed,
- On Windows, run the executable
/artifacts/back/target/usc.exe. For other OS, usejava -jar back-0.10.0-SNAPSHOT-app.jarin folder/artifacts/back/target/ - Browse to http://localhost:8080/ and Discover Devices. HiPeristaltic should be discovered now.
Continue with example calibration scenario:
- Fill in the tubings (e.g., with pure water) by running a pump channel, for instance by using
StartPumpCalibrationwithPumpIndex : 0,RPM : 40,TargetRevolutions : 50and with the correct direction set bycwfor clockwise andccwfor counter-clockwise. - Once this task is finished, place a container which is already weighted when empty, and run
StartPumpCalibrationwith desired parameters, note theTargetRevolutionsvalue. - Weight the container again and calculate the pumped liquid weight. Convert the weight to volume in microliters using the density of the liquid.
- Divide the volume with
TargetRevolutionsto obtain calibration factor with units "microliters per revolution". UseSetPumpCalibrationfunction with this calibration factor.
There are a total of 4 software layers:
- Firmware for the MCU
- Python interface, directly interacting with the firmware
- SiLa2 server, wrapping the Python driver, running on a dedicated computer
- SiLa2 client, in any SiLa2 supported language (Python, Java, C#) or using web application GUI (Universal SiLa client)
After deciding on the MCU, the motor drivers' GPIO pins must be set in the corresponding firmware. Once the firmware is compiled and flashed, the pump can be connected via USB and can be controlled directly with Python interface. A more elegant alternative is controlling the pump through SiLa2 that ideally runs on a dedicated Single Board Computer (SBC).
This next sections outline all steps used to setting up of such dedicated SiLa2 server on an Rasberry Pi SBC. The included Rasberry Pi image is also created using these steps.
- Insert the SD card into your PC.
- Download Raspberry Pi Imager from here and run the software.
- Select the Raspberry Pi device (Raspberry Pi 4 Model B was used for the publication).
- For Operating System, select Raspberry Pi OS (other).
- Select the latest Raspberry Pi OS Lite (64-bit).
- Select the inserted SD card.
- Press Next.
- In Edit Settings
- Under the GENERAL tab:
- Check Set hostname and set to
hiernpi.local. - Check Set username and password (example, please change) and set Username:
hte, Password:hte2025.
- Check Set hostname and set to
- Under the SERVICES tab:
- Enable SSH.
- Select "Use password authentication".
- Under the OPTIONS tab:
- Check Eject media when finished.
- Uncheck Enable telemetry.
- Under the GENERAL tab:
- Press Save.
- Press Yes to apply OS customization settings.
- Press Yes to continue.
- Once finished, remove the SD card and insert it into the Raspberry Pi.
Install/enable OpenSSH on Windows using the following Administrative PowerShell command: 1. Press Windows + X and open Windows PowerShell (Admin). 2. Run the following command: ```bash Add-WindowsCapability -Online -Name OpenSSH.Client~~~~0.0.1.0
For a Linux server to which the MCU is connected, the process starts by SSH'ing into the server. For Windows based servers, we don't have a guide yet.
Following steps are tested with Raspberry Pi. For other Linux systems, you might need to enable UART manually or connect via USB and point to serial port of connection by changing the following part in HiPeristaltic.toml:
Example:
"serial_port" = "tty/USB0"
Again for Rasberry Pi, setup_hiperistaltic.sh should take of everything, but you might need to change the username dependent paths. E.g., hte to someusername.
-
Download:
cd ~ curl -L -O "https://github.com/gunakkoc/HiPeristaltic/raw/refs/heads/main/setup_hiperistaltic.sh"
The script is designed for Raspberry Pi OS. Remove the following lines for other Debian based distros.
# Enable UART echo "Enabling UART..." sudo raspi-config nonint do_serial_hw 0 sudo raspi-config nonint do_serial_cons 1
-
Give execution permission:
sudo chmod +x ~/setup_hiperistaltic.sh -
Run the installation script:
sudo ./setup_hiperistaltic.sh
The typical installation steps are outlined in detail here for Raspberry Pi. For your own application, a change to username-dependent paths might be required. E.g., /home/hte/ to /home/someusername.
The raspi-config commands are also Rasberry Pi specific.
-
Enable UART (recommended)
sudo raspi-config nonint do_serial_hw 0 sudo raspi-config nonint do_serial_cons 1
-
Alternatively, connect the MCU board (i.e., BIGTREETECH SKR MINI E3 V3.0) to the Raspberry Pi via USB. A new device should show up with the command
ls /dev/tty*such as/dev/ttyACM0. Note this device name.
-
Download mini-forge:
curl -L -O "https://github.com/conda-forge/miniforge/releases/latest/download/Miniforge3-$(uname)-$(uname -m).sh" -
Install mini-forge:
bash Miniforge3-$(uname)-$(uname -m).sh -b
-
Finalize mini-forge installation:
~/miniforge3/bin/conda init source ~/.bashrc
The terminal should now show
(base)as the prefix. -
Create a new environment with Python 3.9:
conda create -n hiperis python=3.9
Type y and press Enter to proceed.
-
Activate the environment:
conda activate hiperis
-
Ensure pip is installed:
conda install pip
-
Install necessary libraries:
pip install numpy pyserial toml sila2 sila2[codegen] sila2[cryptography]
-
Install Git:
sudo apt install git
-
Download HiPeristaltic SiLa2/Python Interface:
curl -L -O "https://github.com/gunakkoc/HiPeristaltic/raw/refs/heads/main/silav2/HiPeristaltic.zip" -
Unzip to the home directory:
unzip HiPeristaltic.zip -d ~
This script can be used to (manually) start the HiPeristaltic SiLa2 server.
-
Create a new
.shfile to be executed on startup:nano ~/run_hiperistaltic.sh -
Type the following inside the file:
#!/bin/bash # Get the first IPv4 address (excluding loopback) CA_PATH=~/HiPeristaltic/HiPeristaltic_CA.pem IP_ADDR=$(hostname -I | awk '{print $1}') source ~/miniforge3/etc/profile.d/conda.sh conda activate hiperis cd ~/HiPeristaltic python -m HiPeristaltic --ip-address "$IP_ADDR" --port 50052 --ca-export-file "$CA_PATH"
-
Make the script executable:
sudo chmod +x ~/run_hiperistaltic.sh
Enable starting the HiPeristaltic SiLav2 server automatically when the system boots.
-
Create a systemd service file:
sudo nano /etc/systemd/system/hiperistaltic.service
-
Type the following inside the file:
[Unit] Description=Run HiPeristaltic SiLa2 Server After=network.target [Service] WorkingDirectory=/home/hte/ ExecStart=/bin/bash /home/hte/run_hiperistaltic.sh Restart=always [Install] WantedBy=multi-user.target
-
Enable the service to start on boot:
sudo systemctl enable hiperistaltic -
Reboot:
sudo reboot
To cover the most common microcontroller platforms, 3 firmwares are provided:
- For STM32 platform: tested with STM32G0B1RET6.
- Utilizes an included driver for TMC2209 to maximize performance.
- Requires STM32Cube and STM32 debugger.
- Both UART and USB are supported. Defaults to UART, switches to USB connection automatically if USB connection is detected and until reboot.
- For Arduino platform: tested with Arduino Uno Rev3 (ATmega328P) and Arduino Mega 2560 (ATmega2560)
- Can be compiled with other Arduino compatible platforms such as
stm32duino - Can not be directly connected to Raspberry Pi models over UART. Hence, USB only.
- Can be compiled with other Arduino compatible platforms such as
- Raspberry Pi Pico, tested with Raspberry Pi Pico (RP2040) and Raspberry Pi Pico 2 (RP2350)
- Can be connected Raspberry Pi models over UART.
The GPIO pins for motor drivers needs to be changed accordingly in the firmware unless BIGTREETECH SKR Mini E3 v3.0 is used.
When connecting via USB, the serial port needs to be set in the configuration file HiPeristaltic.toml, for instance:
"serial_port" = "tty/USB0"
Basically all 2-phase stepper drivers that can operate with an step pin can be used, including:
- A4988
- DRV8825
- TMC2208
- TMC2209
- TB6600
- DM556
The recommended board that is BIGTREETECH SKR Mini E3 v3.0 comes with 4 TMC2209 stepper motor drivers embedded. If budget is the ultimate concern, perhaps the cheapest alternative is using an Arduino+CNC Shield combo with A4988 drivers attached.
With the provided STM32 firmware, TMC2209 drivers on the BIGTREETECH SKR Mini E3 v3.0 are controlled via UART communication which allows further optimizations as well as adjustable microstepping on-the-fly. All other firmwares treat TMC2209 as a standard stepper driver.
Moreover, for standard stepper drivers or for other firmwares, the active microstepping value (e.g., 1, 2, 4, 8 and so on) needs to be specified in the HiPeristaltic.toml file, per driver. Alternatively, one can implement their own microstepping changing functionality (i.e., by switching microstepping/resolution pins) and enable it within the firmware.
The following connectivity options are available, depending on the selected MCU, firmware and interface combination.
- SiLa2 over Ethernet or WiFi.
- Serial over USB for direct PC to MCU communication, without SiLa2 layer.
- Serial over UART, typically supported only by SBCs such as Raspberry Pi.
The default configuration file is HiPeristaltic.toml, and by default within the same folder as HiPeristalticInterface.py. Usually, no modifications to this file are necessary. However, if the stepper motor driver is using a fixed microstepping, this needs to be defined in HiPeristaltic.toml (e.g., motor_usteps = 16). Additionally, if the connected computer is not using the standart UART serial port of Rasberry Pi computer (such as a generic Windows computer), then serial_port setting also needs to set up correctly.
The calibration factor can be accessed under calibration_uL_per_Rev for each pump from the HiPeristaltic.toml file. Note that the provided SiLa2 client can be used to remotely change this parameter which is then immediately saved to this file.
The Python interface can be used to control the pump over USB serial and without SiLa2. It is built with minimum dependencies, with only additional libraries being numpy and pySerial.
Here are some examples of essential functionalities using the Python interface:
test = HiPeristalticInterface()
#load config and connect
test.load_config() #loads HiPeristaltic.toml within the same folder by default
test.connect()
#print some informations about the first channel (0 indexed)
print("Max RPM of Pump 1:",test.pumps[0].get_max_rpm())
print("Max volume(L) of Pump 1:",(test.pumps[0].get_max_volume_uL() / 1e6))
print("Min volume(uL) of Pump 1:",test.pumps[0].get_min_volume_uL())
print("Max flow rate(uL/s) of Pump 1:",test.pumps[0].get_max_flow_rate_uLpersec())
print("Min flow rate(uL/s) of Pump 1:",test.pumps[0].get_min_flow_rate_uLpersec())
#run the pumps; cw: clockwise, ccw: counter-clockwise, blocking=True blocks until the pumping task is over, blocking=False continues to next line without waiting
test.pumps[3].pump_volume(target_volume_uL=60,flow_rate_uLpersec=12,direction="cw",blocking=True)
test.pumps[1].pump_continuous(flow_rate_uLpersec=10,direction="cw")
test.pumps[2].pump_continuous(flow_rate_uLpersec=10,direction="ccw")
test.pumps[0].pump_volume(target_volume_uL=120,flow_rate_uLpersec=12,direction="ccw",blocking=False)
#query status
print("Flow rate (uL/s): ", test.pumps[0].get_flow_rate_uLpersec())
while test.pumps[0].get_running():
print("Remaining time (s):" , test.pumps[0].get_remaining_time().total_seconds())
print("Remaining volume (uL):" , test.pumps[0].get_remaining_volume_uL())
sleep(1)
#stop, start, resume a pump
test.pumps[2].pump_stop()
test.pumps[2].pump_volume(target_volume_uL=60,flow_rate_uLpersec=12,direction="cw",blocking=False)
sleep(1)
test.pumps[2].pump_stop()
sleep(1)
test.pumps[2].pump_resume()
while test.pumps[2].get_running():
print("Remaining time (s):" , test.pumps[2].get_remaining_time().total_seconds())
print("Remaining volume (uL):" , test.pumps[2].get_remaining_volume_uL())
sleep(0.5)
#change some config and save
test.pumps[i].uL_per_rev = 60 #change calibration factor
pump.save_config()