


Our research involves generating numerous amino acid sequences predicted to be useful by AI and assaying them to demonstrate the utility of our system. Performing all these tasks manually would require considerable labor and time. Moreover, human experimental operations can present challenges in ensuring reproducibility through standardization of procedures. Therefore, we developed devices to automate relatively simple experimental operations at low cost.
We created two devices: one that automates electrophoresis and imaging, and another that automates inversion mixing. Each device was constructed primarily using 3D-printed components and readily available parts. Furthermore, we minimized the number of components to enable users to easily implement these devices in their experiments.
We developed a device that performs electrophoresis powered by an AC adapter. Additionally, we created a device that automatically captures images of gels after electrophoresis is complete (Fig. 1).

Fig. 1: Overview of the electrophoresis device
Assemble the device and connect the Arduino to a computer to launch the preview application.
After setting the gel in the device and applying DNA samples, place the top part and begin electrophoresis. After running for the specified time, the bottom LED illuminates and the gel is photographed.
The electrophoresis chamber utilizes a plastic container, with the electrode and agarose gel mounting components fabricated using a 3D printer (Fig. 2).

Fig. 2: Electrophoresis chamber
A 12V AC adapter serves as the power source, which is boosted by a DC-DC converter to secure sufficient voltage for electrophoresis. Furthermore, the distance between electrodes is shortened compared to conventional electrophoresis devices to increase migration speed.
A relay switch controls the current flowing between the electrodes, enabling physical interruption of current at the set time (Fig. 3).

Fig. 3: DC-DC converter and relay switch
Upon completion of electrophoresis, the LED at the bottom of the device illuminates to excite the fluorescent dye previously added to the DNA.
A standard webcam is used to capture the fluorescence. To accommodate various webcam models, cable ties are used for mounting to the device.
The software is built using Flet, a Python library, and allows users to view captured images along with their capture timestamps.
Electrophoresis
To verify that the electrophoresis chamber and circuit function correctly, we performed electrophoresis using a DNA ladder marker.
The figure below shows the gel after 90 minutes of electrophoresis. The results demonstrate that electrophoresis was performed correctly with no variation depending on comb position (this gel was imaged using existing imaging equipment) (Fig. 4).

Fig. 4: Gel after electrophoresis
When operating the electrophoresis device, several problems were identified.
The first issue is the slow migration speed. With a 12V input, the voltage could not be raised sufficiently, resulting in approximately one-third the migration speed compared to conventional electrophoresis devices.
Potential solutions include increasing the input voltage from the AC adapter or using a voltage booster circuit capable of higher output voltage.
The second issue is that the stainless steel electrodes dissolved during electrophoresis. This poses problems regarding waste disposal and safety, necessitating replacement with more stable titanium or platinum electrodes.

Circuit diagram for the electrophoresis device

Circuit diagram for the bottom LED

Circuit board connecting DC jack, DC-DC converter, and fan (front side)

Circuit board connecting DC jack, DC-DC converter, and fan (back side)
Cut stainless steel electrodes to 120mm and solder 20AWG (thick) copper wire to one end. Protect the connection between electrode and copper wire with heat-shrink tubing. Bend approximately 10mm of the end with the attached copper wire.
Set the stainless steel electrodes in the middle part of the electrophoresis device and bend the end without copper wire slightly to secure. Connect the electrodes using male T-type connectors.

Electrode wiring diagram

DC-DC converter wiring diagram
Construct the bottom LED circuit. Position LEDs to illuminate the gel evenly.
Wire the Arduino, tactile switch, relay module, and bottom LED using jumper wires.
Stack components from bottom to top in the following order: bottom LED, electrophoresis tank bottom parts, plastic container, electrophoresis tank middle parts, electrophoresis tank top parts.

Assembly diagram for 3D-printed parts and container
Install an orange filter to cover the webcam lens.
Mount the webcam on top of the electrophoresis tank top parts using cable ties.
Upload the source code to the Arduino.
Launch the software following the Preview Software Usage instructions.
| Part Name | Model Number | Quantity | Notes |
|---|---|---|---|
| Electrophoresis tank top parts | 1 | 3D-printed using PLA | |
| Electrophoresis tank middle parts | 1 | 3D-printed using PLA | |
| Electrophoresis tank bottom parts | 1 | 3D-printed using PLA | |
| Plastic container | 1 | Dimensions: 170mm × 120mm × 55mm height | |
| Webcam | UCAM-C980FBBK | 1 | Standard webcams can be used |
| Orange filter | 1 | ||
| Electrodes | 2 | 1.2mm stainless steel wire | |
| DC jack | AE-DC-POWER-JACK-DIP | 1 | DIP-type |
| Relay module | 1 | Product equipped with JQC-3FF-S-Z | |
| DC-DC converter | 1 | DROK 8-32V to 8-46V converter | |
| 12V 3A AC adapter | 1 | ||
| 6cm PC fan | 1 | 12V operation | |
| Copper wire for electrophoresis chamber | 1 | 20AWG for high voltage/current | |
| DC voltage display DC 0-100V | 1 | Required to monitor DC-DC converter output voltage | |
| Blue LEDs | 12 | Use LEDs matching the excitation wavelength of the dye | |
| 10kΩ resistors | 12 | ||
| Jumper wires | For wiring except electrophoresis chamber | ||
| Arduino Uno R3 | 1 | ELEGOO compatible board used | |
| T-type connector (male) | 2 | ||
| T-type connector (female) | 2 | ||
| Heat-shrink tubing | Approx. 30cm | Diameter sufficient to cover T-connector base | |
| Universal circuit board | 1 (optional) | Size: 5×7cm, thickness: 1.2mm, hole pitch: 2.54mm (0.1 inch). Convenient for connecting DC-DC converter, relay module, and fan |
Install Python (Version 3.3 or later) on your computer.
python -m venv .venv
For Windows (command prompt):
.venv\Scripts\activate.bat
For Mac/Linux:
source .venv/bin/activate
(.venv) C:\Users\...
pip install opencv-python pyserial flet
The program execution environment setup is now complete.
Arduino
const int outputPin = 2;
const int inputPin = 4;
const int LEDPin = 5;
// 3600000ms = 1hour
unsigned long ELECTROPHORESIS_TIME = 1000 * 60 * 60;
void setup()
{
Serial.begin(9600);
pinMode(outputPin, OUTPUT);
pinMode(LEDPin, OUTPUT);
pinMode(inputPin, INPUT_PULLUP);
}
void loop()
{
if (digitalRead(inputPin) == LOW)
{
digitalWrite(outputPin, HIGH);
unsigned long start_time = millis();
unsigned long current_time = millis();
while (current_time - start_time < ELECTROPHORESIS_TIME)
{
current_time = millis();
}
digitalWrite(LEDPin, HIGH);
Serial.println("capture"); // Send instruction to PC
delay(3000);
while (true)
{
digitalWrite(outputPin, LOW);
if (digitalRead(inputPin) == LOW)
{
break;
}
}
}
}
Preview Software
import cv2
import serial
import flet as ft
from datetime import datetime
# Select Arduino Serial port
ser = serial.Serial('COM4', 9600)
# Web camera initialization
cap = cv2.VideoCapture(1)
def main(page: ft.Page):
t = ft.Text(value="Figure", color="black")
page.add(t)
page.update()
if not cap.isOpened():
print("Cannot connect Web camera")
exit()
print("Waiting...")
while True:
monitor_Serialport(page)
def monitor_Serialport(page):
if ser.in_waiting > 0:
line = ser.readline().decode('utf-8').strip()
print(f"Recieve: {line}")
if line == "capture":
ret, frame = cap.read()
if ret:
now = datetime.now()
filename = f"photo_{now.strftime("%Y%m%d%H%M%S")}.jpg"
cv2.imwrite(filename, frame)
print(f"saved: {filename}")
ft_image = ft.Image(src=filename, width=600, height=400)
page.add(ft_image)
ft_time = ft.Text(value=now, color="black")
page.add(ft_time)
page.update()
else:
print("failed to get iamge")
ft.app(target=main)
cap.release()
ser.close()
To automate inversion mixing operations, we developed a servo motor-driven inversion mixer and a controller that continuously adjusts mixing speed and displays remaining mixing time (Fig. 5).

Fig. 5: Overview of the inversion mixer
After powering on the device, pressing the black switch on the controller adds 10 minutes to the mixing time. The inversion mixing speed can be adjusted by rotating the knob on the controller. The device stops when the remaining mixing time reaches zero.
The SG90 servo motor provides the motive power for mixing.
This is an inexpensive, compact servo motor that is readily available and possesses sufficient torque for inversion mixing of microcentrifuge tubes.
The base and arm of the drive mechanism were fabricated using a 3D printer (Fig. 6).

Fig. 6: Drive mechanism of the inversion mixer
An Arduino UNO controls the entire device. It is readily available and equipped with sufficient digital pins to operate the seven-segment LED display. Additionally, it can control the servo motor via PWM control.
A potentiometer serves as the knob for continuously adjusting mixing speed. As a type of variable resistor, it can continuously vary voltage. The continuously varying voltage is read by a sensor, enabling continuous control of the servo motor’s movement speed.
The remaining time until completion of inversion mixing is displayed on a seven-segment LED (Fig. 7).

Fig. 7: Controller
The inversion mixer operates by connecting the Arduino to a computer or mobile battery for power supply.
The remaining time display on the seven-segment LED is achieved through timer-based interrupt control, while the extension of mixing time is implemented through interrupt control triggered by signals from the tactile switch.
This enables constant acceptance of operations to the inversion mixer without significantly interfering with servo motor operation.
To confirm the performance of the inversion mixer and its ability to withstand prolonged operation, we conducted 80 minutes of inversion mixing with microcentrifuge tubes containing two types of paint and water.
The figure below confirms that the two types of paint were mixed, although some undissolved material remained (Fig. 8, Fig. 9).

Fig. 8: Sample before mixing

Fig. 9: Sample after mixing
When wet lab members of iGEM TSUKUBA used this device, the following feedback was received:
Reproducibility cannot be ensured without displaying mixing speed in RPM or similar units.
The servo motor is loud during operation.
The mixing time display is unnecessary as smartphone timers can be used instead.
To address these issues, we determined that the motor driving the arm needs to be changed. Therefore, we decided to replace the servo motor with a stepper motor and are currently developing an improved version of the device.

Circuit diagram for the inversion mixer




Controller wiring example (front side)

Controller wiring example (back side)
| Part Name | Model Number | Quantity | Notes |
|---|---|---|---|
| Servo motor | SG-90 | 1 | |
| Mixer base | 1 | 3D-printed using PLA | |
| Mixer arm | 1 | 3D-printed using PLA | |
| M2 12mm screws & nuts | 2 | For securing servo motor to mixer base | |
| M3 30mm screw | 1 | For mixer arm rotation axis | |
| Seven-segment 4-digit LED | 5641AS | 1 | Common cathode type |
| 220Ω resistors | 4 | ||
| Potentiometer | RK09D117000B | 1 | |
| Tactile switch | DTS-63-N-V-BLK(TS-0606-F-N-BLK) | 1 | |
| 10kΩ resistor | 1 | ||
| Breadboard jumper wires | 10-20 | Required when constructing circuit on breadboard | |
| Jumper wires (male-female) | 17 | ||
| Universal circuit board | 2 | Size: 5×7cm, thickness: 1.2mm, hole pitch: 2.54mm (0.1 inch) | |
| Pin header | PH-1x40SG | 20 | |
| Arduino Uno R3 | 1 | ELEGOO compatible board used |
To run this code, download the VarSpeedServo.h library zip file from the internet and install it in Arduino IDE via Sketch → Include Library → ADD .Zip Library… by selecting the downloaded folder.
#include <VarSpeedServo.h>
VarSpeedServo myservo;
int servoPin = 3;
int buttonPin = 2;
int potentiometerPin = 2;
int potentionVal = 0;
long pitchVal = 0;
// pin for Seven-segment display (a~g, dp)
int pinA = A0;
int pinB = A1;
int pinC = 4;
int pinD = 5;
int pinE = 11;
int pinF = 12;
int pinG = 13;
int pinDP = 6;
// digit of Seven-segment display
int D1 = 7;
int D2 = 8;
int D3 = 9;
int D4 = 10;
int segs[8] = {pinA, pinB, pinC, pinD, pinE, pinF, pinG, pinDP};
int digits[4] = {D1, D2, D3, D4};
// signal pattern of Seven-segment display
const int numbers[10][7] = {
{1, 1, 1, 1, 1, 1, 0}, // 0
{0, 1, 1, 0, 0, 0, 0}, // 1
{1, 1, 0, 1, 1, 0, 1}, // 2
{1, 1, 1, 1, 0, 0, 1}, // 3
{0, 1, 1, 0, 0, 1, 1}, // 4
{1, 0, 1, 1, 0, 1, 1}, // 5
{1, 0, 1, 1, 1, 1, 1}, // 6
{1, 1, 1, 0, 0, 0, 0}, // 7
{1, 1, 1, 1, 1, 1, 1}, // 8
{1, 1, 1, 1, 0, 1, 1} // 9
};
// variable for timer
volatile int minutes = 0;
volatile int seconds = 0;
unsigned long lastUpdate = 0;
// For display
volatile int currentDigit = 0;
volatile unsigned long lastButtonPress = 0;
// define interrupt function for timer
ISR(TIMER2_COMPA_vect)
{
unsigned long now = millis();
// count down
if (now - lastUpdate >= 1000)
{
lastUpdate = now;
if (minutes > 0 || seconds > 0)
{
if (seconds > 0)
{
seconds--;
}
else if (minutes > 0)
{
minutes--;
seconds = 59;
}
}
}
int d[4];
d[0] = (minutes / 10) % 10;
d[1] = minutes % 10;
d[2] = (seconds / 10) % 10;
d[3] = seconds % 10;
for (int i = 0; i < 4; i++)
digitalWrite(digits[i], HIGH);
// select signal pattern
for (int i = 0; i < 7; i++)
{
digitalWrite(segs[i], numbers[d[currentDigit]][i] ? HIGH : LOW);
}
digitalWrite(pinDP, (currentDigit == 1) ? HIGH : LOW);
// select digit
digitalWrite(digits[currentDigit], LOW);
currentDigit = (currentDigit + 1) % 4;
}
void setup()
{
for (int i = 0; i < 8; i++)
pinMode(segs[i], OUTPUT);
for (int i = 0; i < 4; i++)
{
pinMode(digits[i], OUTPUT);
digitalWrite(digits[i], HIGH);
}
myservo.attach(servoPin);
myservo.write(0, 30, true);
pinMode(buttonPin, INPUT);
Serial.begin(9600);
// initialize interrupt function for adding mixing time
attachInterrupt(digitalPinToInterrupt(buttonPin), addTime, FALLING);
// initialize timer
cli();
TCCR2A = 0;
TCCR2B = 0;
TCNT2 = 0;
OCR2A = 249;
TCCR2A |= (1 << WGM21);
TCCR2B |= (1 << CS22) | (1 << CS21);
TIMSK2 |= (1 << OCIE2A);
sei();
}
// function for adding mixing time
void addTime()
{
unsigned long now = millis();
if (now - lastButtonPress > 200)
{
minutes = minutes + 10;
Serial.println("added");
lastButtonPress = now;
}
}
void upArm(long speedVal)
{
myservo.write(180, speedVal, true);
}
void downArm(long speedVal)
{
myservo.write(0, speedVal, true);
}
void loop()
{
while (minutes == 0 && seconds == 0)
{
Serial.println("Waiting");
}
pitchVal = map(analogRead(potentiometerPin), 0, 1023, 20, 200);
upArm(pitchVal);
pitchVal = map(analogRead(potentiometerPin), 0, 1023, 20, 200);
downArm(pitchVal);
}
We developed devices to achieve a high-throughput experimental environment through laboratory automation. The electrophoresis device was designed to automate electrophoresis and imaging, successfully realizing high-voltage electrophoresis at relatively low cost.
The inversion mixer can be assembled inexpensively and easily by utilizing a servo motor, and its functionality was validated in actual wet lab experiments. Furthermore, validation revealed insights from the wet lab environment, such as issues with operational noise and reproducibility, enabling improvements to the device design.





© 2025 - Content on this site is licensed under a Creative Commons Attribution 4.0 International license
The repository used to create this website is available at gitlab.igem.org/2025/tsukuba.